From: Douglas Gregor Date: Mon, 16 Aug 2010 23:05:20 +0000 (+0000) Subject: Implement support for cached code completions for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a5fb7c3b56c3698e19a7c1e97d41150de33cf6c9;p=clang Implement support for cached code completions for nested-name-specifiers. Also includes fixes to the generation of nested-name-specifier result in the non-cached case; we were producing lame results for namespaces and namespace aliases, which (1) didn't always have nested-name-specifiers when we want them, and (2) did not have the necessary "::" as part of the completion. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111203 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 564ef56c97..41c5dbc460 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -92,7 +92,10 @@ void ASTUnit::CleanTemporaryFiles() { /// \brief Determine the set of code-completion contexts in which this /// declaration should be shown. static unsigned getDeclShowContexts(NamedDecl *ND, - const LangOptions &LangOpts) { + const LangOptions &LangOpts, + bool &IsNestedNameSpecifier) { + IsNestedNameSpecifier = false; + if (isa(ND)) ND = dyn_cast(ND->getUnderlyingDecl()); if (!ND) @@ -122,19 +125,19 @@ static unsigned getDeclShowContexts(NamedDecl *ND, if (isa(ND)) { Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)); - // Part of the nested-name-specifier. + // Part of the nested-name-specifier in C++0x. if (LangOpts.CPlusPlus0x) - Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1)); + IsNestedNameSpecifier = true; } else if (RecordDecl *Record = dyn_cast(ND)) { if (Record->isUnion()) Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1)); else Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); - // Part of the nested-name-specifier. if (LangOpts.CPlusPlus) - Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1)); - } + IsNestedNameSpecifier = true; + } else if (isa(ND) || isa(ND)) + IsNestedNameSpecifier = true; } else if (isa(ND) || isa(ND)) { // Values can appear in these contexts. Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1)) @@ -143,20 +146,10 @@ static unsigned getDeclShowContexts(NamedDecl *ND, } else if (isa(ND)) { Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); } else if (isa(ND) || isa(ND)) { - Contexts = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) - | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) - | (1 << (CodeCompletionContext::CCC_Statement - 1)) - | (1 << (CodeCompletionContext::CCC_Expression - 1)) - | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) - | (1 << (CodeCompletionContext::CCC_Namespace - 1)); + Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1)); // Part of the nested-name-specifier. - Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1)) - | (1 << (CodeCompletionContext::CCC_EnumTag - 1)) - | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) - | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)) - | (1 << (CodeCompletionContext::CCC_Type - 1)); + IsNestedNameSpecifier = true; } return Contexts; @@ -188,10 +181,12 @@ void ASTUnit::CacheCodeCompletionResults() { for (unsigned I = 0, N = Results.size(); I != N; ++I) { switch (Results[I].Kind) { case Result::RK_Declaration: { + bool IsNestedNameSpecifier = false; CachedCodeCompletionResult CachedResult; CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, - Ctx->getLangOptions()); + Ctx->getLangOptions(), + IsNestedNameSpecifier); CachedResult.Priority = Results[I].Priority; CachedResult.Kind = Results[I].CursorKind; @@ -220,6 +215,41 @@ void ASTUnit::CacheCodeCompletionResults() { } CachedCompletionResults.push_back(CachedResult); + + /// Handle nested-name-specifiers in C++. + if (TheSema->Context.getLangOptions().CPlusPlus && + IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) { + // The contexts in which a nested-name-specifier can appear in C++. + unsigned NNSContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_EnumTag - 1)) + | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) + | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)) + | (1 << (CodeCompletionContext::CCC_Type - 1)); + + if (isa(Results[I].Declaration) || + isa(Results[I].Declaration)) + NNSContexts |= (1 << (CodeCompletionContext::CCC_Namespace - 1)); + + if (unsigned RemainingContexts + = NNSContexts & ~CachedResult.ShowInContexts) { + // If there any contexts where this completion can be a + // nested-name-specifier but isn't already an option, create a + // nested-name-specifier completion. + Results[I].StartsNestedNameSpecifier = true; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts = RemainingContexts; + CachedResult.Priority = CCP_NestedNameSpecifier; + CachedResult.TypeClass = STC_Void; + CachedResult.Type = 0; + CachedCompletionResults.push_back(CachedResult); + } + } break; } @@ -1482,8 +1512,8 @@ void CalculateHiddenNames(const CodeCompletionContext &Context, Hiding = (IDNS & Decl::IDNS_Tag); else { unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | - Decl::IDNS_Namespace | Decl::IDNS_Ordinary | - Decl::IDNS_NonMemberOperator); + Decl::IDNS_Namespace | Decl::IDNS_Ordinary | + Decl::IDNS_NonMemberOperator); if (Ctx.getLangOptions().CPlusPlus) HiddenIDNS |= Decl::IDNS_Tag; Hiding = (IDNS & HiddenIDNS); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 332f8c8029..d61c430141 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -426,6 +426,12 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, if (isa(ND)) return false; + if (Filter == &ResultBuilder::IsNestedNameSpecifier || + ((isa(ND) || isa(ND)) && + Filter != &ResultBuilder::IsNamespace && + Filter != &ResultBuilder::IsNamespaceOrAlias)) + AsNestedNameSpecifier = true; + // Filter out any unwanted results. if (Filter && !(this->*Filter)(ND)) { // Check whether it is interesting as a nested-name-specifier. @@ -439,11 +445,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, } return false; - } - - if (Filter == &ResultBuilder::IsNestedNameSpecifier) - AsNestedNameSpecifier = true; - + } // ... then it must be interesting! return true; } diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp index 1d50fd3469..cd0317f153 100644 --- a/test/Index/code-completion.cpp +++ b/test/Index/code-completion.cpp @@ -15,9 +15,9 @@ struct Z : X, Y { double member; operator int() const; }; - +struct W { }; struct Z get_Z(); - +namespace N { } void test_Z() { // RUN: c-index-test -code-completion-at=%s:23:11 %s | FileCheck -check-prefix=CHECK-MEMBER %s get_Z().member = 17; @@ -64,4 +64,4 @@ Z::operator int() const { // CHECK-EXPR: FieldDecl:{ResultType int}{Text X::}{TypedText member} (5) // CHECK-EXPR: FieldDecl:{ResultType float}{Text Y::}{TypedText member} (11) // CHECK-EXPR: FunctionDecl:{ResultType void}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )} (22) - +// CHECK-EXPR: NotImplemented:{TypedText N}{Text ::} (75)