Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -5161,7 +5161,14 @@ * \brief Whether to include brief documentation within the set of code * completions returned. */ - CXCodeComplete_IncludeBriefComments = 0x04 + CXCodeComplete_IncludeBriefComments = 0x04, + + /** + * \brief Whether to speed up completion by omitting some entities which are + * defined in the preamble. There's no guarantee any particular entity will + * be omitted. This may be useful if the headers are indexed externally. + */ + CXCodeComplete_SkipPreamble = 0x08 }; /** Index: include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- include/clang/Sema/CodeCompleteConsumer.h +++ include/clang/Sema/CodeCompleteConsumer.h @@ -934,6 +934,12 @@ return CodeCompleteOpts.IncludeBriefComments; } + /// \brief Hint whether to load data from the external AST in order to provide + /// full results. If false, declarations from the preamble may be omitted. + bool loadExternal() const { + return CodeCompleteOpts.LoadExternal; + } + /// \brief Determine whether the output of this consumer is binary. bool isOutputBinary() const { return OutputIsBinary; } Index: include/clang/Sema/CodeCompleteOptions.h =================================================================== --- include/clang/Sema/CodeCompleteOptions.h +++ include/clang/Sema/CodeCompleteOptions.h @@ -35,9 +35,14 @@ /// Show brief documentation comments in code completion results. unsigned IncludeBriefComments : 1; + /// Hint whether to load data from the external AST in order to provide + /// full results. If false, declarations from the preamble may be omitted. + unsigned LoadExternal : 1; + CodeCompleteOptions() : IncludeMacros(0), IncludeCodePatterns(0), IncludeGlobals(1), - IncludeNamespaceLevelDecls(1), IncludeBriefComments(0) {} + IncludeNamespaceLevelDecls(1), IncludeBriefComments(0), + LoadExternal(1) {} }; } // namespace clang Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3199,11 +3199,11 @@ void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope = true); + bool IncludeGlobalScope = true, bool Load = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, - bool IncludeDependentBases = false); + bool IncludeDependentBases = false, bool Load = true); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. Index: lib/Frontend/ASTUnit.cpp =================================================================== --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -2068,6 +2068,7 @@ CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns; CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty(); CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments; + CodeCompleteOpts.LoadExternal = Consumer.loadExternal(); assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion); Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -3524,7 +3524,8 @@ CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); @@ -3599,7 +3600,8 @@ Results.setFilter(&ResultBuilder::IsImpossibleToSatisfy); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.setFilter(nullptr); } } @@ -3669,8 +3671,9 @@ CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + Results.EnterNewScope(); AddOrdinaryNameResults(PCC_Expression, S, *this, Results); Results.ExitScope(); @@ -3939,7 +3942,8 @@ CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext); SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, SemaRef.CodeCompleter->includeGlobals(), - /*IncludeDependentBases=*/true); + /*IncludeDependentBases=*/true, + SemaRef.CodeCompleter->loadExternal()); if (SemaRef.getLangOpts().CPlusPlus) { if (!Results.empty()) { @@ -4049,8 +4053,9 @@ if (Class) { CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.setFilter(&ResultBuilder::IsObjCIvar); - LookupVisibleDecls(Class, LookupMemberName, Consumer, - CodeCompleter->includeGlobals()); + LookupVisibleDecls( + Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(), + /*IncludeDependentBases=*/false, CodeCompleter->loadExternal()); } } @@ -4124,12 +4129,15 @@ // First pass: look for tags. Results.setFilter(Filter); LookupVisibleDecls(S, LookupTagName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); if (CodeCompleter->includeGlobals()) { // Second pass: look for nested name specifiers. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); } HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), @@ -4540,8 +4548,9 @@ CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + AddOrdinaryNameResults(PCC_Statement, S, *this, Results); // "else" block @@ -4649,7 +4658,8 @@ CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/true, - /*IncludeDependentBases=*/true); + /*IncludeDependentBases=*/true, + CodeCompleter->loadExternal()); } auto CC = Results.getCompletionContext(); @@ -4677,7 +4687,8 @@ // nested-name-specifier. CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -4698,7 +4709,8 @@ Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Namespace, @@ -4764,7 +4776,8 @@ &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); @@ -4791,8 +4804,9 @@ Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + // Add any type specifiers AddTypeSpecifierResults(getLangOpts(), Results); Results.ExitScope(); @@ -5620,8 +5634,9 @@ Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false); @@ -5834,8 +5849,9 @@ CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + // If we are in an Objective-C method inside a class that has a superclass, // add "super" as an option. if (ObjCMethodDecl *Method = getCurMethodDecl()) @@ -7942,8 +7958,9 @@ if (!CodeCompleter || CodeCompleter->includeGlobals()) { CodeCompletionDeclConsumer Consumer(Builder, Context.getTranslationUnitDecl()); - LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, - Consumer); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, + Consumer, + !CodeCompleter || CodeCompleter->loadExternal()); } if (!CodeCompleter || CodeCompleter->includeMacros()) Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -3498,7 +3498,8 @@ bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited, - bool IncludeDependentBases = false) { + bool IncludeDependentBases, + bool Load) { if (!Ctx) return; @@ -3513,11 +3514,12 @@ auto &Idents = S.Context.Idents; // Ensure all external identifiers are in the identifier table. - if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { - std::unique_ptr Iter(External->getIdentifiers()); - for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) - Idents.get(Name); - } + if (Load) + if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { + std::unique_ptr Iter(External->getIdentifiers()); + for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) + Idents.get(Name); + } // Walk all lookup results in the TU for each identifier. for (const auto &Ident : Idents) { @@ -3540,7 +3542,8 @@ Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContextLookupResult R : Ctx->lookups()) { + for (DeclContextLookupResult R : + Load ? Ctx->lookups() : Ctx->noload_lookups()) { for (auto *D : R) { if (auto *ND = Result.getAcceptableDecl(D)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); @@ -3557,7 +3560,7 @@ continue; LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases); + IncludeDependentBases, Load); } } @@ -3614,7 +3617,7 @@ // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer, - Visited, IncludeDependentBases); + Visited, IncludeDependentBases, Load); } } @@ -3623,22 +3626,22 @@ // Traverse categories. for (auto *Cat : IFace->visible_categories()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, - Consumer, Visited); + LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, + Visited, IncludeDependentBases, Load); } // Traverse protocols. for (auto *I : IFace->all_referenced_protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, Load); } // Traverse the superclass. if (IFace->getSuperClass()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, - true, Consumer, Visited); + true, Consumer, Visited, IncludeDependentBases, Load); } // If there is an implementation, traverse it. We do this to find @@ -3646,26 +3649,28 @@ if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getImplementation(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited); + QualifiedNameLookup, InBaseClass, Consumer, Visited, + IncludeDependentBases, Load); } } else if (ObjCProtocolDecl *Protocol = dyn_cast(Ctx)) { for (auto *I : Protocol->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, Load); } } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { for (auto *I : Category->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, Load); } // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Category->getImplementation(), Result, - QualifiedNameLookup, true, Consumer, Visited); + QualifiedNameLookup, true, Consumer, Visited, + IncludeDependentBases, Load); } } } @@ -3673,7 +3678,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, UnqualUsingDirectiveSet &UDirs, VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited) { + VisibleDeclsRecord &Visited, + bool Load) { if (!S) return; @@ -3712,7 +3718,8 @@ Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, Load); } } @@ -3726,7 +3733,8 @@ continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, Load); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation @@ -3740,7 +3748,8 @@ // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, Load); } if (Entity) { @@ -3749,17 +3758,18 @@ for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) LookupVisibleDecls(const_cast(UUE.getNominatedNamespace()), Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, Load); } // Lookup names in the parent scope. ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited); + LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited, Load); } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope) { + bool IncludeGlobalScope, bool Load) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; @@ -3780,13 +3790,13 @@ if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); + ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, Load); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, - bool IncludeDependentBases) { + bool IncludeDependentBases, bool Load) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; @@ -3795,7 +3805,7 @@ ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited, - IncludeDependentBases); + IncludeDependentBases, Load); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. Index: test/Index/complete-pch-skip.h =================================================================== --- /dev/null +++ test/Index/complete-pch-skip.h @@ -0,0 +1,3 @@ +namespace ns { +int foo; +} Index: test/Index/complete-pch-skip.cpp =================================================================== --- /dev/null +++ test/Index/complete-pch-skip.cpp @@ -0,0 +1,18 @@ +namespace ns { +int bar; +} + +int main() { return ns:: } + +// RUN: echo "namespace ns { int foo; }" > %t.h +// RUN: c-index-test -write-pch %t.h.pch -x c++-header %t.h +// +// RUN: c-index-test -code-completion-at=%s:5:26 -include %t.h %s | FileCheck -check-prefix=WITH-PCH %s +// WITH-PCH: {TypedText bar} +// WITH-PCH: {TypedText foo} + +// RUN: env CINDEXTEST_COMPLETION_SKIP_PREAMBLE=1 c-index-test -code-completion-at=%s:5:26 -include %t.h %s | FileCheck -check-prefix=SKIP-PCH %s +// SKIP-PCH-NOT: foo +// SKIP-PCH: {TypedText bar} +// SKIP-PCH-NOT: foo + Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -2326,6 +2326,8 @@ completionOptions |= CXCodeComplete_IncludeCodePatterns; if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS")) completionOptions |= CXCodeComplete_IncludeBriefComments; + if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE")) + completionOptions |= CXCodeComplete_SkipPreamble; if (timing_only) input += strlen("-code-completion-timing="); Index: tools/libclang/CIndexCodeCompletion.cpp =================================================================== --- tools/libclang/CIndexCodeCompletion.cpp +++ tools/libclang/CIndexCodeCompletion.cpp @@ -643,6 +643,7 @@ ArrayRef unsaved_files, unsigned options) { bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; + bool SkipPreamble = options & CXCodeComplete_SkipPreamble; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT @@ -689,6 +690,7 @@ // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; + Opts.LoadExternal = !SkipPreamble; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion.