From: Douglas Gregor Date: Sun, 15 Aug 2010 06:18:01 +0000 (+0000) Subject: Extend the code-completion caching infrastructure to include global X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8071e4212ae08f8014e0c3ae6d18b7388003a5cc;p=clang Extend the code-completion caching infrastructure to include global declarations (in addition to macros). Each kind of declaration maps to a certain set of completion contexts, and the ASTUnit completion logic introduces the completion strings for those declarations if the actual code-completion occurs in one of the contexts where it matters. There are a few new code-completion-context kinds. Without these, certain completions (e.g., after "using namespace") would need to suppress all global completions, which would be unfortunate. Note that we don't get the priorities right for global completions, because we don't have enough type information. We'll need a way to compare types in an ASTContext-agnostic way before this can be implemented. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111093 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index bfa8c8ba02..ea7175da53 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -264,6 +264,8 @@ def code_completion_macros : Flag<"-code-completion-macros">, HelpText<"Include macros in code-completion results">; def code_completion_patterns : Flag<"-code-completion-patterns">, HelpText<"Include code patterns in code-completion results">; +def no_code_completion_globals : Flag<"-no-code-completion-globals">, + HelpText<"Do not include global declarations in code-completion results.">; def disable_free : Flag<"-disable-free">, HelpText<"Disable freeing of memory on exit">; def help : Flag<"-help">, diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index bd1791dae8..2a0a7a7747 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -544,7 +544,8 @@ public: createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, unsigned Line, unsigned Column, bool UseDebugPrinter, bool ShowMacros, - bool ShowCodePatterns, llvm::raw_ostream &OS); + bool ShowCodePatterns, bool ShowGlobals, + llvm::raw_ostream &OS); /// \brief Create the Sema object to be used for parsing. void createSema(bool CompleteTranslationUnit, diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 48ce5074fa..e24f3a0be1 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -69,6 +69,8 @@ public: /// results. unsigned ShowCodePatternsInCodeCompletion : 1; ///< Show code patterns in code /// completion results. + unsigned ShowGlobalSymbolsInCodeCompletion : 1; ///< Show top-level decls in + /// code completion results. unsigned ShowStats : 1; ///< Show frontend performance /// metrics and statistics. unsigned ShowTimers : 1; ///< Show timers for individual @@ -122,6 +124,7 @@ public: ShowHelp = 0; ShowMacrosInCodeCompletion = 0; ShowCodePatternsInCodeCompletion = 0; + ShowGlobalSymbolsInCodeCompletion = 1; ShowStats = 0; ShowTimers = 0; ShowVersion = 0; diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index 48e422383f..16dd69d401 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -127,7 +127,12 @@ public: /// to indicate a struct or class name. CCC_ClassOrStructTag, /// \brief Code completion occurred where a protocol name is expected. - CCC_ObjCProtocolName + CCC_ObjCProtocolName, + /// \brief Code completion occurred where a namespace or namespace alias + /// is expected. + CCC_Namespace, + /// \brief Code completion occurred where a type name is expected. + CCC_Type }; private: @@ -382,6 +387,10 @@ protected: /// the completion results. bool IncludeCodePatterns; + /// \brief Whether to include global (top-level) declarations and names in + /// the completion results. + bool IncludeGlobals; + /// \brief Whether the output format for the code-completion consumer is /// binary. bool OutputIsBinary; @@ -588,12 +597,12 @@ public: }; CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false), - OutputIsBinary(false) { } + IncludeGlobals(true), OutputIsBinary(false) { } CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, - bool OutputIsBinary) + bool IncludeGlobals, bool OutputIsBinary) : IncludeMacros(IncludeMacros), IncludeCodePatterns(IncludeCodePatterns), - OutputIsBinary(OutputIsBinary) { } + IncludeGlobals(IncludeGlobals), OutputIsBinary(OutputIsBinary) { } /// \brief Whether the code-completion consumer wants to see macros. bool includeMacros() const { return IncludeMacros; } @@ -601,6 +610,9 @@ public: /// \brief Whether the code-completion consumer wants to see code patterns. bool includeCodePatterns() const { return IncludeCodePatterns; } + /// \brief Whether to include global (top-level) declaration results. + bool includeGlobals() const { return IncludeGlobals; } + /// \brief Determine whether the output of this consumer is binary. bool isOutputBinary() const { return OutputIsBinary; } @@ -639,8 +651,10 @@ public: /// \brief Create a new printing code-completion consumer that prints its /// results to the given raw output stream. PrintingCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeGlobals, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, false), OS(OS) {} + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, + false), OS(OS) {} /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, @@ -664,8 +678,9 @@ public: /// results to the given raw output stream in a format readable to the CIndex /// library. CIndexCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, - llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, true), OS(OS) {} + bool IncludeGlobals, llvm::raw_ostream &OS) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, + true), OS(OS) {} /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5ef8e5f070..a57a5a78c7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1486,7 +1486,9 @@ public: /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up the name of an Objective-C protocol. - LookupObjCProtocolName + LookupObjCProtocolName, + /// \brief Look up any declaration with any name. + LookupAnyName }; /// \brief Specifies whether (or how) name lookup is being performed for a @@ -1534,9 +1536,11 @@ public: ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, - VisibleDeclConsumer &Consumer); + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, - VisibleDeclConsumer &Consumer); + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); /// \brief The context in which typo-correction occurs. /// diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index e6bae6b727..8d49d4e786 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -88,6 +88,79 @@ void ASTUnit::CleanTemporaryFiles() { TemporaryFiles.clear(); } +/// \brief Determine the set of code-completion contexts in which this +/// declaration should be shown. +static unsigned getDeclShowContexts(NamedDecl *ND, + const LangOptions &LangOpts) { + if (isa(ND)) + ND = dyn_cast(ND->getUnderlyingDecl()); + if (!ND) + return 0; + + unsigned Contexts = 0; + if (isa(ND) || isa(ND) || + isa(ND) || isa(ND)) { + // Types can appear in these contexts. + if (LangOpts.CPlusPlus || !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_Type - 1)); + + // In C++, types can appear in expressions contexts (for functional casts). + if (LangOpts.CPlusPlus) + Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1)); + + // In Objective-C, message sends can send interfaces. In Objective-C++, + // all types are available due to functional casts. + if (LangOpts.CPlusPlus || isa(ND)) + Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + + // Deal with tag names. + if (isa(ND)) { + Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)); + + // Part of the nested-name-specifier. + if (LangOpts.CPlusPlus0x) + Contexts |= (1 << (CodeCompletionContext::CCC_MemberAccess - 1)); + } 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)); + } + } else if (isa(ND) || isa(ND)) { + // Values can appear in these contexts. + Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + } 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)); + + // 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)); + } + + return Contexts; +} + void ASTUnit::CacheCodeCompletionResults() { if (!TheSema) return; @@ -111,10 +184,17 @@ void ASTUnit::CacheCodeCompletionResults() { // Translate global code completions into cached completions. for (unsigned I = 0, N = Results.size(); I != N; ++I) { switch (Results[I].Kind) { - case Result::RK_Declaration: - // FIXME: Handle declarations! + case Result::RK_Declaration: { + CachedCodeCompletionResult CachedResult; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, + Ctx->getLangOptions()); + CachedResult.Priority = Results[I].Priority; + CachedResult.Kind = Results[I].CursorKind; + CachedCompletionResults.push_back(CachedResult); break; - + } + case Result::RK_Keyword: case Result::RK_Pattern: // Ignore keywords and patterns; we don't care, since they are so @@ -1287,8 +1367,9 @@ namespace { public: AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, - bool IncludeMacros, bool IncludeCodePatterns) - : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, + bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeGlobals) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, Next.isOutputBinary()), AST(AST), Next(Next) { // Compute the set of contexts in which we will look when we don't have @@ -1387,6 +1468,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOpts.ShowMacrosInCodeCompletion = IncludeMacros && CachedCompletionResults.empty(); FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns; + FrontendOpts.ShowGlobalSymbolsInCodeCompletion + = CachedCompletionResults.empty(); FrontendOpts.CodeCompletionAt.FileName = File; FrontendOpts.CodeCompletionAt.Line = Line; FrontendOpts.CodeCompletionAt.Column = Column; @@ -1447,7 +1530,8 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // code-completion results. AugmentedCodeCompleteConsumer AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion, - FrontendOpts.ShowCodePatternsInCodeCompletion); + FrontendOpts.ShowCodePatternsInCodeCompletion, + FrontendOpts.ShowGlobalSymbolsInCodeCompletion); Clang.setCodeCompletionConsumer(&AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 06ec80589c..8e1dbcb9d2 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -328,6 +328,7 @@ void CompilerInstance::createCodeCompletionConsumer() { getFrontendOpts().DebugCodeCompletionPrinter, getFrontendOpts().ShowMacrosInCodeCompletion, getFrontendOpts().ShowCodePatternsInCodeCompletion, + getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, llvm::outs())); if (!CompletionConsumer) return; @@ -356,15 +357,18 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, bool UseDebugPrinter, bool ShowMacros, bool ShowCodePatterns, + bool ShowGlobals, llvm::raw_ostream &OS) { if (EnableCodeCompletion(PP, Filename, Line, Column)) return 0; // Set up the creation routine for code-completion. if (UseDebugPrinter) - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + ShowGlobals, OS); else - return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); + return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + ShowGlobals, OS); } void CompilerInstance::createSema(bool CompleteTranslationUnit, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index aa6888bd1d..5605f16dac 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -363,6 +363,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-code-completion-macros"); if (Opts.ShowCodePatternsInCodeCompletion) Res.push_back("-code-completion-patterns"); + if (!Opts.ShowGlobalSymbolsInCodeCompletion) + Res.push_back("-no-code-completion-globals"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) @@ -1047,6 +1049,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowCodePatternsInCodeCompletion = Args.hasArg(OPT_code_completion_patterns); + Opts.ShowGlobalSymbolsInCodeCompletion + = !Args.hasArg(OPT_no_code_completion_globals); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 31185683a1..599a10fd90 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2308,7 +2308,8 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, } CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.EnterNewScope(); AddOrdinaryNameResults(CompletionContext, S, *this, Results); @@ -2340,7 +2341,8 @@ void Sema::CodeCompleteExpression(Scope *S, QualType T, Results.setPreferredType(T.getNonReferenceType()); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.EnterNewScope(); AddOrdinaryNameResults(PCC_Expression, S, *this, Results); @@ -2432,7 +2434,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // Access to a C/C++ class, struct, or union. Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer); + LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer, + CodeCompleter->includeGlobals()); if (getLangOptions().CPlusPlus) { if (!Results.empty()) { @@ -2480,7 +2483,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, if (Class) { CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.setFilter(&ResultBuilder::IsObjCIvar); - LookupVisibleDecls(Class, LookupMemberName, Consumer); + LookupVisibleDecls(Class, LookupMemberName, Consumer, + CodeCompleter->includeGlobals()); } } @@ -2530,11 +2534,14 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // First pass: look for tags. Results.setFilter(Filter); - LookupVisibleDecls(S, LookupTagName, Consumer); + LookupVisibleDecls(S, LookupTagName, Consumer, + CodeCompleter->includeGlobals()); - // Second pass: look for nested name specifiers. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + if (CodeCompleter->includeGlobals()) { + // Second pass: look for nested name specifiers. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + } HandleCodeCompleteResults(this, CodeCompleter, ContextKind, Results.data(),Results.size()); @@ -2836,7 +2843,8 @@ void Sema::CodeCompleteUsing(Scope *S) { // After "using", we can see anything that would start a // nested-name-specifier. CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -2853,10 +2861,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_Namespace, Results.data(),Results.size()); } @@ -2903,9 +2912,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_Namespace, Results.data(),Results.size()); } @@ -2926,14 +2936,15 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add any type names visible from the current scope Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); // Add any type specifiers AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_Type, Results.data(),Results.size()); } @@ -3514,7 +3525,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { Results.setFilter(&ResultBuilder::IsObjCMessageReceiver); CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); // If we are in an Objective-C method inside a class that has a superclass, // add "super" as an option. @@ -4341,13 +4353,12 @@ void Sema::GatherGlobalCodeCompletions( llvm::SmallVectorImpl &Results) { ResultBuilder Builder(*this); -#if 0 - // FIXME: We need a name lookup that means "look for everything", - CodeCompletionDeclConsumer Consumer(Builder, - Context.getTranslationUnitDecl()); - LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupOrdinaryName, - Consumer); -#endif + if (!CodeCompleter || CodeCompleter->includeGlobals()) { + CodeCompletionDeclConsumer Consumer(Builder, + Context.getTranslationUnitDecl()); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, + Consumer); + } if (!CodeCompleter || CodeCompleter->includeMacros()) AddMacroResults(PP, Builder); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 1ffea89acd..994b633db8 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -254,6 +254,12 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; + + case Sema::LookupAnyName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member + | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol + | Decl::IDNS_Type; + break; } return IDNS; } @@ -1199,6 +1205,17 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, return Found; } +/// \brief Callback that looks for any member of a class with the given name. +static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + Path.Decls = BaseRecord->lookup(N); + return Path.Decls.first != Path.Decls.second; +} + /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -1294,6 +1311,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &CXXRecordDecl::FindTagMember; break; + case LookupAnyName: + BaseCallback = &LookupAnyMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. @@ -2223,6 +2244,10 @@ public: return !VisitedContexts.insert(Ctx); } + bool alreadyVisitedContext(DeclContext *Ctx) { + return VisitedContexts.count(Ctx); + } + /// \brief Determine whether the given declaration is hidden in the /// current scope. /// @@ -2503,7 +2528,9 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; - if (!S->getEntity() || !S->getParent() || + if (!S->getEntity() || + (!S->getParent() && + !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); @@ -2581,7 +2608,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, - VisibleDeclConsumer &Consumer) { + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; @@ -2598,14 +2626,19 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, // Look for visible declarations. LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; + if (!IncludeGlobalScope) + Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, - VisibleDeclConsumer &Consumer) { + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; + if (!IncludeGlobalScope) + Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c index ef19d1484d..7dfe280d9e 100644 --- a/test/Index/complete-exprs.c +++ b/test/Index/complete-exprs.c @@ -19,6 +19,12 @@ const char *str = "Hello, \nWorld"; // CHECK-CC1-NOT: NotImplemented:{TypedText float} (40) // CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (2) // CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1a %s +// FIXME: Priorities aren't right +// CHECK-CC1a: ParmDecl:{ResultType int}{TypedText j} (2) +// CHECK-CC1a: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) +// CHECK-CC1a: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50) +// CHECK-CC1a: macro definition:{TypedText __VERSION__} (70) // RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: macro definition:{TypedText __VERSION__} (70) diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index f0e90212f7..48bbe7d46b 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -547,7 +547,8 @@ namespace { public: explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) - : CodeCompleteConsumer(true, false, false), AllocatedResults(Results) { } + : CodeCompleteConsumer(true, false, true, false), + AllocatedResults(Results) { } virtual void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,