diff options
-rw-r--r-- | include/clang/Sema/CodeCompleteConsumer.h | 47 | ||||
-rw-r--r-- | lib/Sema/CodeCompleteConsumer.cpp | 44 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 63 | ||||
-rw-r--r-- | test/CodeCompletion/member-access.cpp | 18 | ||||
-rw-r--r-- | test/CodeCompletion/namespace-alias.cpp | 4 | ||||
-rw-r--r-- | test/CodeCompletion/operator.cpp | 2 | ||||
-rw-r--r-- | test/CodeCompletion/tag.cpp | 10 | ||||
-rw-r--r-- | test/CodeCompletion/using-namespace.cpp | 4 | ||||
-rw-r--r-- | test/CodeCompletion/using.cpp | 6 |
9 files changed, 124 insertions, 74 deletions
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 68e07e9608..6a10b28be9 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -48,7 +48,10 @@ public: CK_Optional, /// \brief A string that acts as a placeholder for, e.g., a function /// call argument. - CK_Placeholder + CK_Placeholder, + /// \brief A piece of text that describes something about the result but + /// should not be inserted into the buffer. + CK_Informative }; /// \brief One piece of the code completion string. @@ -58,7 +61,8 @@ public: ChunkKind Kind; union { - /// \brief The text string associated with a CK_Text chunk. + /// \brief The text string associated with a CK_Text, CK_Placeholder, + /// or CK_Informative chunk. /// The string is owned by the chunk and will be deallocated /// (with delete[]) when the chunk is destroyed. const char *Text; @@ -67,13 +71,14 @@ public: /// The optional code completion string is owned by the chunk, and will /// be deallocated (with delete) when the chunk is destroyed. CodeCompletionString *Optional; - - /// \brief Placeholder text associated with a CK_Placeholder chunk. - /// The string is owned by the chunk and will be deallocated (with - /// delete[]) when the chunk is destroyed. - const char *Placeholder; }; + Chunk() : Kind(CK_Text), Text(0) { } + + private: + Chunk(ChunkKind Kind, const char *Text); + + public: /// \brief Create a new text chunk. static Chunk CreateText(const char *Text); @@ -82,7 +87,10 @@ public: /// \brief Create a new placeholder chunk. static Chunk CreatePlaceholder(const char *Placeholder); - + + /// \brief Create a new informative chunk. + static Chunk CreateInformative(const char *Informative); + /// \brief Destroy this chunk, deallocating any memory it owns. void Destroy(); }; @@ -118,6 +126,12 @@ public: void AddPlaceholderChunk(const char *Placeholder) { Chunks.push_back(Chunk::CreatePlaceholder(Placeholder)); } + + /// \brief Add a new informative chunk. + /// The text will be copied. + void AddInformativeChunk(const char *Text) { + Chunks.push_back(Chunk::CreateInformative(Text)); + } /// \brief Retrieve a string representation of the code completion string, /// which is mainly useful for debugging. @@ -156,19 +170,26 @@ public: /// \brief Whether this result is hidden by another name. bool Hidden : 1; - /// \brief If the result requires a nested-name-specifier for name lookup - /// to function properly, this is the nested-name-specifier. + /// \brief Whether this result was found via lookup into a base class. + bool QualifierIsInformative : 1; + + /// \brief If the result should have a nested-name-specifier, this is it. + /// When \c QualifierIsInformative, the nested-name-specifier is + /// informative rather than required. NestedNameSpecifier *Qualifier; /// \brief Build a result that refers to a declaration. Result(NamedDecl *Declaration, unsigned Rank, - NestedNameSpecifier *Qualifier = 0) + NestedNameSpecifier *Qualifier = 0, + bool QualifierIsInformative = false) : Kind(RK_Declaration), Declaration(Declaration), Rank(Rank), - Hidden(false), Qualifier(Qualifier) { } + Hidden(false), QualifierIsInformative(QualifierIsInformative), + Qualifier(Qualifier) { } /// \brief Build a result that refers to a keyword or symbol. Result(const char *Keyword, unsigned Rank) - : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false) { } + : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), Hidden(false), + QualifierIsInformative(0), Qualifier(0) { } /// \brief Retrieve the declaration stored in this result. NamedDecl *getDeclaration() const { diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 1e505090fb..f490a2b523 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -26,14 +26,19 @@ using namespace clang; //===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// -CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateText(const char *Text) { - Chunk Result; - Result.Kind = CK_Text; +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) + : Kind(Kind), Text(0) +{ + assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative) + && "Invalid text chunk kind"); char *New = new char [std::strlen(Text) + 1]; std::strcpy(New, Text); - Result.Text = New; - return Result; + this->Text = New; +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateText(const char *Text) { + return Chunk(CK_Text, Text); } CodeCompletionString::Chunk @@ -47,20 +52,26 @@ CodeCompletionString::Chunk::CreateOptional( CodeCompletionString::Chunk CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { - Chunk Result; - Result.Kind = CK_Placeholder; - char *New = new char [std::strlen(Placeholder) + 1]; - std::strcpy(New, Placeholder); - Result.Placeholder = New; - return Result; + return Chunk(CK_Placeholder, Placeholder); +} + +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateInformative(const char *Informative) { + return Chunk(CK_Informative, Informative); } void CodeCompletionString::Chunk::Destroy() { switch (Kind) { - case CK_Text: delete [] Text; break; - case CK_Optional: delete Optional; break; - case CK_Placeholder: delete [] Placeholder; break; + case CK_Optional: + delete Optional; + break; + + case CK_Text: + case CK_Placeholder: + case CK_Informative: + delete [] Text; + break; } } @@ -77,7 +88,8 @@ std::string CodeCompletionString::getAsString() const { switch (C->Kind) { case CK_Text: OS << C->Text; break; case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; - case CK_Placeholder: OS << "<#" << C->Placeholder << "#>"; break; + case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; + case CK_Informative: OS << "[#" << C->Text << "#]"; break; } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b19fda216d..f57480e13e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -197,8 +197,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Look through using declarations. if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration)) - return MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), - CurContext); + MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), + CurContext); // Handle each declaration in an overload set separately. if (OverloadedFunctionDecl *Ovl @@ -281,6 +281,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { I->second.first)) { // Note that this result was hidden. R.Hidden = true; + R.QualifierIsInformative = false; if (!R.Qualifier) R.Qualifier = getRequiredQualification(SemaRef.Context, @@ -300,6 +301,18 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (!AllDeclsFound.insert(CanonDecl)) return; + // If this result is supposed to have an informative qualifier, add one. + if (R.QualifierIsInformative && !R.Qualifier) { + DeclContext *Ctx = R.Declaration->getDeclContext(); + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace); + else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false, + SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + else + R.QualifierIsInformative = false; + } + // Insert this result into the set of results and into the current shadow // map. SMap.insert(std::make_pair(R.Declaration->getDeclName(), @@ -398,9 +411,7 @@ static DeclContext *findOuterContext(Scope *S) { /// /// \param Ctx the declaration context from which we will gather results. /// -/// \param InitialRank the initial rank given to results in this declaration -/// context. Larger rank values will be used for, e.g., members found in -/// base classes. +/// \param Rank the rank given to results in this declaration context. /// /// \param Visited the set of declaration contexts that have already been /// visited. Declaration contexts will only be visited once. @@ -408,18 +419,22 @@ static DeclContext *findOuterContext(Scope *S) { /// \param Results the result set that will be extended with any results /// found within this declaration context (and, for a C++ class, its bases). /// +/// \param InBaseClass whether we are in a base class. +/// /// \returns the next higher rank value, after considering all of the /// names within this declaration context. static unsigned CollectMemberLookupResults(DeclContext *Ctx, - unsigned InitialRank, + unsigned Rank, DeclContext *CurContext, llvm::SmallPtrSet<DeclContext *, 16> &Visited, - ResultBuilder &Results) { + ResultBuilder &Results, + bool InBaseClass = false) { // Make sure we don't visit the same context twice. if (!Visited.insert(Ctx->getPrimaryContext())) - return InitialRank; + return Rank; // Enumerate all of the results in this context. + typedef CodeCompleteConsumer::Result Result; Results.EnterNewScope(); for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; CurCtx = CurCtx->getNextContext()) { @@ -427,13 +442,11 @@ static unsigned CollectMemberLookupResults(DeclContext *Ctx, DEnd = CurCtx->decls_end(); D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) - Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, InitialRank), - CurContext); + Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext); } } // Traverse the contexts of inherited classes. - unsigned NextRank = InitialRank; if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); @@ -468,19 +481,15 @@ static unsigned CollectMemberLookupResults(DeclContext *Ctx, // c->A::member // Collect results from this base class (and its bases). - NextRank = std::max(NextRank, - CollectMemberLookupResults(Record->getDecl(), - InitialRank + 1, - CurContext, - Visited, - Results)); + CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited, + Results, /*InBaseClass=*/true); } } // FIXME: Look into base classes in Objective-C! Results.ExitScope(); - return NextRank; + return Rank + 1; } /// \brief Collect the results of searching for members within the given @@ -735,6 +744,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, /// provided nested-name-specifier is non-NULL. void AddQualifierToCompletionString(CodeCompletionString *Result, NestedNameSpecifier *Qualifier, + bool QualifierIsInformative, ASTContext &Context) { if (!Qualifier) return; @@ -744,7 +754,10 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, llvm::raw_string_ostream OS(PrintedNNS); Qualifier->print(OS, Context.PrintingPolicy); } - Result->AddTextChunk(PrintedNNS.c_str()); + if (QualifierIsInformative) + Result->AddInformativeChunk(PrintedNNS.c_str()); + else + Result->AddTextChunk(PrintedNNS.c_str()); } /// \brief If possible, create a new code completion string for the given @@ -762,7 +775,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { CodeCompletionString *Result = new CodeCompletionString; - AddQualifierToCompletionString(Result, Qualifier, S.Context); + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); Result->AddTextChunk(Function->getNameAsString().c_str()); Result->AddTextChunk("("); AddFunctionParameterChunks(S.Context, Function, Result); @@ -772,7 +786,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { CodeCompletionString *Result = new CodeCompletionString; - AddQualifierToCompletionString(Result, Qualifier, S.Context); + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); Result->AddTextChunk(Function->getNameAsString().c_str()); @@ -825,7 +840,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { CodeCompletionString *Result = new CodeCompletionString; - AddQualifierToCompletionString(Result, Qualifier, S.Context); + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); Result->AddTextChunk(Template->getNameAsString().c_str()); Result->AddTextChunk("<"); AddTemplateParameterChunks(S.Context, Template, Result); @@ -835,7 +851,8 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (Qualifier) { CodeCompletionString *Result = new CodeCompletionString; - AddQualifierToCompletionString(Result, Qualifier, S.Context); + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + S.Context); Result->AddTextChunk(ND->getNameAsString().c_str()); return Result; } diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp index cbd19db1a5..b23436d8c8 100644 --- a/test/CodeCompletion/member-access.cpp +++ b/test/CodeCompletion/member-access.cpp @@ -28,15 +28,15 @@ public: void test(const Proxy &p) { p-> // RUN: clang-cc -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CC1 %s && + // CHECK-CC1: member1 : 0 : [#Base1::#]member1 + // CHECK-CC1: member1 : 0 : [#Base2::#]member1 + // CHECK-CC1: member2 : 0 : [#Base1::#]member2 + // CHECK-CC1: member3 : 0 // CHECK-CC1: member4 : 0 - // CHECK-CC1: memfun3 : 0 - // CHECK-CC1: memfun1 : 1 - // CHECK-CC1: memfun1 : 1 - // CHECK-CC1: memfun2 : 1 - // CHECK-CC1: member1 : 2 - // CHECK-CC1: member1 : 2 - // CHECK-CC1: member2 : 2 - // CHECK-CC1: member3 : 2 - // CHECK-CC1: memfun1 : 2 (Hidden) : Base2::memfun1(<#int#>) + // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#float#>) + // CHECK-CC1: memfun1 : 0 : [#Base3::#]memfun1(<#double#>) + // CHECK-CC1: memfun2 : 0 : [#Base3::#]memfun2(<#int#>) + // CHECK-CC1: memfun3 : 0 : memfun3(<#int#>) + // CHECK-CC1: memfun1 : 0 (Hidden) : Base2::memfun1(<#int#>) // RUN: true diff --git a/test/CodeCompletion/namespace-alias.cpp b/test/CodeCompletion/namespace-alias.cpp index cae3d561d1..c92e554e5f 100644 --- a/test/CodeCompletion/namespace-alias.cpp +++ b/test/CodeCompletion/namespace-alias.cpp @@ -15,7 +15,7 @@ namespace N2 { // CHECK-CC1: I1 : 1 // CHECK-CC1: I4 : 1 // CHECK-CC1: I5 : 1 - // CHECK-CC1: N2 : 2 - // CHECK-NEXT-CC1: N4 : 2 + // CHECK-CC1: N2 : 3 + // CHECK-NEXT-CC1: N4 : 3 // RUN: true
\ No newline at end of file diff --git a/test/CodeCompletion/operator.cpp b/test/CodeCompletion/operator.cpp index 72a3f6bb71..a3950f6b89 100644 --- a/test/CodeCompletion/operator.cpp +++ b/test/CodeCompletion/operator.cpp @@ -14,5 +14,5 @@ void f() { // CHECK-CC1: short : 0 // CHECK-CC1: Integer : 2 // CHECK-CC1: T : 2 - // CHECK-CC1: N : 5 + // CHECK-CC1: N : 6 // RUN: true diff --git a/test/CodeCompletion/tag.cpp b/test/CodeCompletion/tag.cpp index 201aec4dd3..2642b7c731 100644 --- a/test/CodeCompletion/tag.cpp +++ b/test/CodeCompletion/tag.cpp @@ -18,9 +18,9 @@ namespace N { // RUN: clang-cc -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CC1 %s && // CHECK-CC1: Y : 2 // CHECK-CC1: Z : 2 - // CHECK-CC1: A : 3 - // CHECK-CC1: X : 3 - // CHECK-CC1: Y : 3 - // CHECK-CC1: M : 6 - // CHECK-CC1: N : 6 + // CHECK-CC1: A : 4 + // CHECK-CC1: X : 4 + // CHECK-CC1: Y : 4 + // CHECK-CC1: M : 9 + // CHECK-CC1: N : 9 // RUN: true diff --git a/test/CodeCompletion/using-namespace.cpp b/test/CodeCompletion/using-namespace.cpp index 95bff9b5ee..3e8cd53723 100644 --- a/test/CodeCompletion/using-namespace.cpp +++ b/test/CodeCompletion/using-namespace.cpp @@ -16,6 +16,6 @@ namespace N2 { // CHECK-CC1: I1 : 2 // CHECK-CC1: I4 : 2 // CHECK-CC1: I5 : 2 - // CHECK-CC1: N2 : 3 - // CHECK-NEXT-CC1: N4 : 3 + // CHECK-CC1: N2 : 4 + // CHECK-NEXT-CC1: N4 : 4 // RUN: true diff --git a/test/CodeCompletion/using.cpp b/test/CodeCompletion/using.cpp index 27b85fc766..dac556e151 100644 --- a/test/CodeCompletion/using.cpp +++ b/test/CodeCompletion/using.cpp @@ -18,8 +18,8 @@ namespace N2 { // CHECK-CC1: I1 : 2 // CHECK-CC1: I4 : 2 // CHECK-CC1: I5 : 2 - // CHECK-CC1: N2 : 3 - // CHECK-CC1: N3 : 3 - // CHECK-NEXT-CC1: N4 : 3 + // CHECK-CC1: N2 : 4 + // CHECK-CC1: N3 : 4 + // CHECK-NEXT-CC1: N4 : 4 // RUN: true |