Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -642,8 +642,10 @@ Result.IncludeGlobals = IncludeGlobals; Result.IncludeBriefComments = IncludeBriefComments; - // Enable index-based code completion when Index is provided. - Result.IncludeNamespaceLevelDecls = !Index; + // When an is used, Sema is responsible for completing the main file, + // the index can provide results from the preamble. + // Tell Sema not to deserialize the preamble to look for results. + Result.LoadExternal = !Index; return Result; } Index: clang-tools-extra/trunk/clangd/index/FileIndex.cpp =================================================================== --- clang-tools-extra/trunk/clangd/index/FileIndex.cpp +++ clang-tools-extra/trunk/clangd/index/FileIndex.cpp @@ -20,6 +20,8 @@ std::shared_ptr PP, llvm::ArrayRef Decls) { SymbolCollector::Options CollectorOpts; + // Code completion gets main-file results from Sema. + // But we leave this option on because features like go-to-definition want it. CollectorOpts.IndexMainFiles = true; auto Collector = std::make_shared(std::move(CollectorOpts)); Collector->setPreprocessor(std::move(PP)); Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -57,6 +57,7 @@ using ::testing::Each; using ::testing::ElementsAre; using ::testing::Not; +using ::testing::UnorderedElementsAre; class IgnoreDiagnostics : public DiagnosticsConsumer { void @@ -104,7 +105,7 @@ /*StorePreamblesInMemory=*/true); auto File = getVirtualTestFilePath("foo.cpp"); Annotations Test(Text); - Server.addDocument(Context::empty(), File, Test.code()); + Server.addDocument(Context::empty(), File, Test.code()).wait(); auto CompletionList = Server.codeComplete(Context::empty(), File, Test.point(), Opts) .get() @@ -506,11 +507,11 @@ Opts.Index = nullptr; auto Results = completions(R"cpp( - namespace ns { class No {}; } + namespace ns { class Local {}; } void f() { ns::^ } )cpp", Opts); - EXPECT_THAT(Results.items, Has("No")); + EXPECT_THAT(Results.items, Has("Local")); } TEST(CompletionTest, StaticAndDynamicIndex) { @@ -538,13 +539,13 @@ Opts.Index = I.get(); auto Results = completions(R"cpp( - namespace ns { class No {}; } + namespace ns { int local; } void f() { ns::^ } )cpp", Opts); EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class)); EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function)); - EXPECT_THAT(Results.items, Not(Has("No"))); + EXPECT_THAT(Results.items, Has("local")); } TEST(CompletionTest, IndexBasedWithFilter) { @@ -585,6 +586,41 @@ EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class)); } +TEST(CompletionTest, IndexSuppressesPreambleCompletions) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(), + /*StorePreamblesInMemory=*/true); + + FS.Files[getVirtualTestFilePath("bar.h")] = + R"cpp(namespace ns { int preamble; })cpp"; + auto File = getVirtualTestFilePath("foo.cpp"); + Annotations Test(R"cpp( + #include "bar.h" + namespace ns { int local; } + void f() { ns::^ } + )cpp"); + Server.addDocument(Context::empty(), File, Test.code()).wait(); + clangd::CodeCompleteOptions Opts = {}; + + auto WithoutIndex = + Server.codeComplete(Context::empty(), File, Test.point(), Opts) + .get() + .second.Value; + EXPECT_THAT(WithoutIndex.items, + UnorderedElementsAre(Named("local"), Named("preamble"))); + + auto I = simpleIndexFromSymbols({{"ns::index", index::SymbolKind::Variable}}); + Opts.Index = I.get(); + auto WithIndex = + Server.codeComplete(Context::empty(), File, Test.point(), Opts) + .get() + .second.Value; + EXPECT_THAT(WithIndex.items, + UnorderedElementsAre(Named("local"), Named("index"))); +} + TEST(CompletionTest, ASTIndexMultiFile) { MockFSProvider FS; MockCompilationDatabase CDB;