[libclang] Replace ObjC generic parameters in code-completion results.

rdar://19369529

llvm-svn: 241557
This commit is contained in:
Douglas Gregor 2015-07-07 06:20:19 +00:00
parent ab7f0b342f
commit c3425b1ff9
7 changed files with 147 additions and 48 deletions

View File

@ -765,11 +765,13 @@ public:
/// \param Allocator The allocator that will be used to allocate the
/// string itself.
CodeCompletionString *CreateCodeCompletionString(Sema &S,
const CodeCompletionContext &CCContext,
CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments);
CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx,
Preprocessor &PP,
const CodeCompletionContext &CCContext,
CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments);

View File

@ -353,6 +353,7 @@ void ASTUnit::CacheCodeCompletionResults() {
// Translate global code completions into cached completions.
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
CodeCompletionContext CCContext(CodeCompletionContext::CCC_TopLevel);
for (Result &R : Results) {
switch (R.Kind) {
@ -360,7 +361,7 @@ void ASTUnit::CacheCodeCompletionResults() {
bool IsNestedNameSpecifier = false;
CachedCodeCompletionResult CachedResult;
CachedResult.Completion = R.CreateCodeCompletionString(
*TheSema, *CachedCompletionAllocator, CCTUInfo,
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = getDeclShowContexts(
R.Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier);
@ -423,7 +424,7 @@ void ASTUnit::CacheCodeCompletionResults() {
// nested-name-specifier completion.
R.StartsNestedNameSpecifier = true;
CachedResult.Completion = R.CreateCodeCompletionString(
*TheSema, *CachedCompletionAllocator, CCTUInfo,
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = RemainingContexts;
CachedResult.Priority = CCP_NestedNameSpecifier;
@ -444,7 +445,7 @@ void ASTUnit::CacheCodeCompletionResults() {
case Result::RK_Macro: {
CachedCodeCompletionResult CachedResult;
CachedResult.Completion = R.CreateCodeCompletionString(
*TheSema, *CachedCompletionAllocator, CCTUInfo,
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts
= (1LL << CodeCompletionContext::CCC_TopLevel)

View File

@ -444,7 +444,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
OS << " : " << CCS->getAsString();
@ -462,7 +463,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
case CodeCompletionResult::RK_Macro: {
OS << Results[I].Macro->getName();
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, getAllocator(),
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
OS << " : " << CCS->getAsString();

View File

@ -2057,6 +2057,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
static void AddResultTypeChunk(ASTContext &Context,
const PrintingPolicy &Policy,
const NamedDecl *ND,
QualType BaseType,
CodeCompletionBuilder &Result) {
if (!ND)
return;
@ -2070,16 +2071,28 @@ static void AddResultTypeChunk(ASTContext &Context,
QualType T;
if (const FunctionDecl *Function = ND->getAsFunction())
T = Function->getReturnType();
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getReturnType();
else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
if (!BaseType.isNull())
T = Method->getSendResultType(BaseType);
else
T = Method->getReturnType();
} else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
} else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) {
if (!BaseType.isNull())
T = Ivar->getUsageType(BaseType);
else
T = Ivar->getType();
} else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
T = Value->getType();
} else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
} else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) {
if (!BaseType.isNull())
T = Property->getUsageType(BaseType);
else
T = Property->getType();
}
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
return;
@ -2140,7 +2153,8 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals,
static std::string FormatFunctionParameter(const PrintingPolicy &Policy,
const ParmVarDecl *Param,
bool SuppressName = false,
bool SuppressBlock = false) {
bool SuppressBlock = false,
Optional<ArrayRef<QualType>> ObjCSubsts = None) {
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
if (Param->getType()->isDependentType() ||
!Param->getType()->isBlockPointerType()) {
@ -2152,6 +2166,9 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy,
Result = Param->getIdentifier()->getName();
QualType Type = Param->getType();
if (ObjCSubsts)
Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts,
ObjCSubstitutionContext::Parameter);
if (ObjCMethodParam) {
Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(),
Type);
@ -2226,6 +2243,10 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy,
// written in the source.
std::string Result;
QualType ResultType = Block.getTypePtr()->getReturnType();
if (ObjCSubsts)
ResultType = ResultType.substObjCTypeArgs(Param->getASTContext(),
*ObjCSubsts,
ObjCSubstitutionContext::Result);
if (!ResultType->isVoidType() || SuppressBlock)
ResultType.getAsStringInternal(Result, Policy);
@ -2243,7 +2264,8 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy,
Params += ", ";
Params += FormatFunctionParameter(Policy, Block.getParam(I),
/*SuppressName=*/false,
/*SuppressBlock=*/true);
/*SuppressBlock=*/true,
ObjCSubsts);
if (I == N - 1 && BlockProto.getTypePtr()->isVariadic())
Params += ", ...";
@ -2537,11 +2559,12 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
}
CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S,
const CodeCompletionContext &CCContext,
CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments) {
return CreateCodeCompletionString(S.Context, S.PP, Allocator, CCTUInfo,
IncludeBriefComments);
return CreateCodeCompletionString(S.Context, S.PP, CCContext, Allocator,
CCTUInfo, IncludeBriefComments);
}
/// \brief If possible, create a new code completion string for the given
@ -2553,6 +2576,7 @@ CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S,
CodeCompletionString *
CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
Preprocessor &PP,
const CodeCompletionContext &CCContext,
CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments) {
@ -2666,7 +2690,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
for (const auto *I : ND->specific_attrs<AnnotateAttr>())
Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation()));
AddResultTypeChunk(Ctx, Policy, ND, Result);
AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
@ -2786,14 +2810,22 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
continue;
std::string Arg;
if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
Arg = FormatFunctionParameter(Policy, *P, true);
QualType ParamType = (*P)->getType();
Optional<ArrayRef<QualType>> ObjCSubsts;
if (!CCContext.getBaseType().isNull())
ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method);
if (ParamType->isBlockPointerType() && !DeclaringEntity)
Arg = FormatFunctionParameter(Policy, *P, true,
/*SuppressBlock=*/false,
ObjCSubsts);
else {
QualType Type = (*P)->getType();
if (ObjCSubsts)
ParamType = ParamType.substObjCTypeArgs(Ctx, *ObjCSubsts,
ObjCSubstitutionContext::Parameter);
Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(),
Type);
Arg += Type.getAsString(Policy) + ")";
ParamType);
Arg += ParamType.getAsString(Policy) + ")";
if (IdentifierInfo *II = (*P)->getIdentifier())
if (DeclaringEntity || AllParametersAreInformative)
Arg += II->getName();
@ -2930,7 +2962,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
if (auto RC = S.getASTContext().getRawCommentForAnyRedecl(
FDecl->getParamDecl(CurrentArg)))
Result.addBriefComment(RC->getBriefText(S.getASTContext()));
AddResultTypeChunk(S.Context, Policy, FDecl, Result);
AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result);
Result.AddTextChunk(
Result.getAllocator().CopyString(FDecl->getNameAsString()));
} else {
@ -3522,7 +3554,8 @@ static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) {
return Container;
}
static void AddObjCProperties(ObjCContainerDecl *Container,
static void AddObjCProperties(const CodeCompletionContext &CCContext,
ObjCContainerDecl *Container,
bool AllowCategories,
bool AllowNullaryMethods,
DeclContext *CurContext,
@ -3549,7 +3582,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
if (AddedProperties.insert(Name).second) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
AddResultTypeChunk(Context, Policy, M, Builder);
AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(),
Builder);
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(Name->getName()));
@ -3564,32 +3598,32 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
// Add properties in referenced protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
for (auto *P : Protocol->protocols())
AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
for (auto *Cat : IFace->known_categories())
AddObjCProperties(Cat, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
}
// Look through protocols.
for (auto *I : IFace->all_referenced_protocols())
AddObjCProperties(I, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
// Look in the superclass.
if (IFace->getSuperClass())
AddObjCProperties(IFace->getSuperClass(), AllowCategories,
AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories,
AllowNullaryMethods, CurContext,
AddedProperties, Results);
} else if (const ObjCCategoryDecl *Category
= dyn_cast<ObjCCategoryDecl>(Container)) {
// Look through protocols.
for (auto *P : Category->protocols())
AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
}
}
@ -3631,11 +3665,11 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
contextKind = CodeCompletionContext::CCC_DotMemberAccess;
}
}
CodeCompletionContext CCContext(contextKind, BaseType);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext(contextKind,
BaseType),
CCContext,
&ResultBuilder::IsMember);
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
@ -3675,14 +3709,14 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
const ObjCObjectPointerType *ObjCPtr
= BaseType->getAsObjCInterfacePointerType();
assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
AddObjCProperties(ObjCPtr->getInterfaceDecl(), true,
AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true,
/*AllowNullaryMethods=*/true, CurContext,
AddedProperties, Results);
// Add properties from the protocols in a qualified interface.
for (auto *I : ObjCPtr->quals())
AddObjCProperties(I, true, /*AllowNullaryMethods=*/true, CurContext,
AddedProperties, Results);
AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true,
CurContext, AddedProperties, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
@ -5336,7 +5370,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(
Results.getCodeCompletionTUInfo());
// Give this completion a return type.
AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod,
AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod,
Results.getCompletionContext().getBaseType(),
Builder);
// If we need the "super" keyword, add it (plus some spacing).
@ -6090,9 +6125,10 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
}
void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
CodeCompletionContext CCContext(CodeCompletionContext::CCC_Other);
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
CCContext);
// Figure out where this @synthesize lives.
ObjCContainerDecl *Container
@ -6113,11 +6149,12 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
Results.EnterNewScope();
if (ObjCImplementationDecl *ClassImpl
= dyn_cast<ObjCImplementationDecl>(Container))
AddObjCProperties(ClassImpl->getClassInterface(), false,
AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false,
/*AllowNullaryMethods=*/false, CurContext,
AddedProperties, Results);
else
AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),
AddObjCProperties(CCContext,
cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),
false, /*AllowNullaryMethods=*/false, CurContext,
AddedProperties, Results);
Results.ExitScope();

View File

@ -0,0 +1,53 @@
@protocol NSObject
@end
@interface NSObject
@end
@interface Test<T : id, U : NSObject *> : NSObject
{
@public
U myVar;
}
-(U)getit:(T)val;
-(void)apply:(void(^)(T, U))block;
@property (strong) T prop;
@end
@interface MyClsA : NSObject
@end
@interface MyClsB : NSObject
@end
void test1(Test<MyClsA*, MyClsB*> *obj) {
[obj ];
obj.;
obj->;
}
void test2(Test *obj) {
[obj ];
obj.;
obj->;
}
// RUN: c-index-test -code-completion-at=%s:24:8 %s | FileCheck -check-prefix=CHECK-CC0 %s
// CHECK-CC0: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply:}{Placeholder ^(MyClsA *, MyClsB *)block} (35)
// CHECK-CC0: ObjCInstanceMethodDecl:{ResultType MyClsB *}{TypedText getit:}{Placeholder (MyClsA *)} (35)
// RUN: c-index-test -code-completion-at=%s:25:7 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCPropertyDecl:{ResultType MyClsA *}{TypedText prop} (35)
// RUN: c-index-test -code-completion-at=%s:26:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCIvarDecl:{ResultType MyClsB *}{TypedText myVar} (35)
// RUN: c-index-test -code-completion-at=%s:30:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType void}{TypedText apply:}{Placeholder ^(id, NSObject *)block} (35)
// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType __kindof NSObject *}{TypedText getit:}{Placeholder (id)} (35)
// RUN: c-index-test -code-completion-at=%s:31:7 %s | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: ObjCPropertyDecl:{ResultType id}{TypedText prop} (35)
// RUN: c-index-test -code-completion-at=%s:32:8 %s | FileCheck -check-prefix=CHECK-CC5 %s
// CHECK-CC5: ObjCIvarDecl:{ResultType __kindof NSObject *}{TypedText myVar} (35)

View File

@ -542,7 +542,7 @@ namespace {
StoredResults.reserve(StoredResults.size() + NumResults);
for (unsigned I = 0; I != NumResults; ++I) {
CodeCompletionString *StoredCompletion
= Results[I].CreateCodeCompletionString(S, getAllocator(),
= Results[I].CreateCodeCompletionString(S, Context, getAllocator(),
getCodeCompletionTUInfo(),
includeBriefComments());

View File

@ -1298,6 +1298,7 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
CodeCompletionString *String
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
CodeCompletionContext::CCC_Other,
unit->getCodeCompletionTUInfo().getAllocator(),
unit->getCodeCompletionTUInfo(),
true);
@ -1308,10 +1309,13 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
const IdentifierInfo *MacroInfo = definition->getName();
ASTUnit *unit = getCursorASTUnit(cursor);
CodeCompletionResult Result(MacroInfo);
CodeCompletionString *String = Result.CreateCodeCompletionString(
unit->getASTContext(), unit->getPreprocessor(),
unit->getCodeCompletionTUInfo().getAllocator(),
unit->getCodeCompletionTUInfo(), false);
CodeCompletionString *String
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
CodeCompletionContext::CCC_Other,
unit->getCodeCompletionTUInfo().getAllocator(),
unit->getCodeCompletionTUInfo(),
false);
return String;
}
return nullptr;