aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h47
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp44
-rw-r--r--lib/Sema/SemaCodeComplete.cpp63
-rw-r--r--test/CodeCompletion/member-access.cpp18
-rw-r--r--test/CodeCompletion/namespace-alias.cpp4
-rw-r--r--test/CodeCompletion/operator.cpp2
-rw-r--r--test/CodeCompletion/tag.cpp10
-rw-r--r--test/CodeCompletion/using-namespace.cpp4
-rw-r--r--test/CodeCompletion/using.cpp6
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