From: Douglas Gregor Date: Tue, 7 Jul 2015 06:20:19 +0000 (+0000) Subject: [libclang] Replace ObjC generic parameters in code-completion results. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=11354e9dc89251a48673f2fe61b0ffe99615b32a;p=clang [libclang] Replace ObjC generic parameters in code-completion results. rdar://19369529 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241557 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index de65c43c76..97022738d0 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -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); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 01c56bdc4d..57c97d0c31 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -353,6 +353,7 @@ void ASTUnit::CacheCodeCompletionResults() { // Translate global code completions into cached completions. llvm::DenseMap 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) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 69ae4f01dc..18e9a59116 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -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(); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e4e99ab993..61e244601f 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -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(ND)) - T = Method->getReturnType(); - else if (const EnumConstantDecl *Enumerator = dyn_cast(ND)) + else if (const ObjCMethodDecl *Method = dyn_cast(ND)) { + if (!BaseType.isNull()) + T = Method->getSendResultType(BaseType); + else + T = Method->getReturnType(); + } else if (const EnumConstantDecl *Enumerator = dyn_cast(ND)) T = Context.getTypeDeclType(cast(Enumerator->getDeclContext())); else if (isa(ND)) { /* Do nothing: ignore unresolved using declarations*/ + } else if (const ObjCIvarDecl *Ivar = dyn_cast(ND)) { + if (!BaseType.isNull()) + T = Ivar->getUsageType(BaseType); + else + T = Ivar->getType(); } else if (const ValueDecl *Value = dyn_cast(ND)) { T = Value->getType(); - } else if (const ObjCPropertyDecl *Property = dyn_cast(ND)) - T = Property->getType(); + } else if (const ObjCPropertyDecl *Property = dyn_cast(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> ObjCSubsts = None) { bool ObjCMethodParam = isa(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()) 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(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> 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(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(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(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()) { @@ -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(Container)) - AddObjCProperties(ClassImpl->getClassInterface(), false, + AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else - AddObjCProperties(cast(Container)->getCategoryDecl(), + AddObjCProperties(CCContext, + cast(Container)->getCategoryDecl(), false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); Results.ExitScope(); diff --git a/test/Index/complete-parameterized-classes.m b/test/Index/complete-parameterized-classes.m new file mode 100644 index 0000000000..2d60eaca95 --- /dev/null +++ b/test/Index/complete-parameterized-classes.m @@ -0,0 +1,53 @@ +@protocol NSObject +@end + +@interface NSObject +@end + +@interface Test : 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 *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) diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index a7b8e29204..9609a693ab 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -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()); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index fe9ba4eac1..099edcf14f 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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;