From: Douglas Gregor Date: Mon, 16 Aug 2010 21:18:39 +0000 (+0000) Subject: Implement name hiding of cached global code-completion results. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f808c2bfe2f95c984029d76deb4aaebcad30cbc;p=clang Implement name hiding of cached global code-completion results. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111184 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 77a641a2c5..d0c08a08ff 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -25,6 +25,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/System/Path.h" #include "llvm/Support/Timer.h" #include diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 2c827e41da..f8dea65d54 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1435,15 +1435,85 @@ namespace { }; } +/// \brief Helper function that computes which global names are hidden by the +/// local code-completion results. +void CalculateHiddenNames(const CodeCompletionContext &Context, + CodeCompleteConsumer::Result *Results, + unsigned NumResults, + ASTContext &Ctx, + llvm::StringSet<> &HiddenNames) { + bool OnlyTagNames = false; + switch (Context.getKind()) { + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_TopLevel: + case CodeCompletionContext::CCC_ObjCInterface: + case CodeCompletionContext::CCC_ObjCImplementation: + case CodeCompletionContext::CCC_ObjCIvarList: + case CodeCompletionContext::CCC_ClassStructUnion: + case CodeCompletionContext::CCC_Statement: + case CodeCompletionContext::CCC_Expression: + case CodeCompletionContext::CCC_ObjCMessageReceiver: + case CodeCompletionContext::CCC_MemberAccess: + case CodeCompletionContext::CCC_Namespace: + case CodeCompletionContext::CCC_Type: + break; + + case CodeCompletionContext::CCC_EnumTag: + case CodeCompletionContext::CCC_UnionTag: + case CodeCompletionContext::CCC_ClassOrStructTag: + OnlyTagNames = true; + break; + + case CodeCompletionContext::CCC_ObjCProtocolName: + // If we're just looking for protocol names, nothing can hide them. + return; + } + + typedef CodeCompleteConsumer::Result Result; + for (unsigned I = 0; I != NumResults; ++I) { + if (Results[I].Kind != Result::RK_Declaration) + continue; + + unsigned IDNS + = Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace(); + + bool Hiding = false; + if (OnlyTagNames) + Hiding = (IDNS & Decl::IDNS_Tag); + else { + unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | + Decl::IDNS_Namespace | Decl::IDNS_Ordinary | + Decl::IDNS_NonMemberOperator); + if (Ctx.getLangOptions().CPlusPlus) + HiddenIDNS |= Decl::IDNS_Tag; + Hiding = (IDNS & HiddenIDNS); + } + + if (!Hiding) + continue; + + DeclarationName Name = Results[I].Declaration->getDeclName(); + if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo()) + HiddenNames.insert(Identifier->getName()); + else + HiddenNames.insert(Name.getAsString()); + } +} + + void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, Result *Results, unsigned NumResults) { // Merge the results we were given with the results we cached. bool AddedResult = false; - unsigned InContexts = - (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts - : (1 << (Context.getKind() - 1))); + unsigned InContexts + = (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts + : (1 << (Context.getKind() - 1))); + + // Contains the set of names that are hidden by "local" completion results. + llvm::StringSet<> HiddenNames; + typedef CodeCompleteConsumer::Result Result; llvm::SmallVector AllResults; for (ASTUnit::cached_completion_iterator @@ -1457,10 +1527,18 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, // If we haven't added any results previously, do so now. if (!AddedResult) { + CalculateHiddenNames(Context, Results, NumResults, S.Context, + HiddenNames); AllResults.insert(AllResults.end(), Results, Results + NumResults); AddedResult = true; } + // Determine whether this global completion result is hidden by a local + // completion result. If so, skip it. + if (C->Kind != CXCursor_MacroDefinition && + HiddenNames.count(C->Completion->getTypedText())) + continue; + // Adjust priority based on similar type classes. unsigned Priority = C->Priority; if (!Context.getPreferredType().isNull()) { diff --git a/test/Index/complete-hiding.c b/test/Index/complete-hiding.c new file mode 100644 index 0000000000..0505abfa47 --- /dev/null +++ b/test/Index/complete-hiding.c @@ -0,0 +1,29 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. + +struct StructA { }; +struct StructB { }; +struct StructC { }; +int ValueA; +int ValueB; + +void f() { + + int ValueA = 0; + int StructA = 0; + struct StructB { }; + + struct StructA sa = { }; +} + +// RUN: c-index-test -code-completion-at=%s:16:3 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:16:3 %s | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: VarDecl:{ResultType int}{TypedText StructA} (8) +// CHECK-CC1: VarDecl:{ResultType int}{TypedText ValueA} (8) +// CHECK-CC1-NOT: VarDecl:{ResultType int}{TypedText ValueA} (50) +// CHECK-CC1: VarDecl:{ResultType int}{TypedText ValueB} (50) +// RUN: c-index-test -code-completion-at=%s:16:10 %s | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: StructDecl:{TypedText StructA} (40) +// CHECK-CC2-NOT: StructDecl:{TypedText StructB} (40) +// CHECK-CC2: StructDecl:{TypedText StructC} (40) +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:16:10 %s | FileCheck -check-prefix=CHECK-CC2 %s