Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -644,8 +644,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: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ 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 @@ -482,11 +483,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) { @@ -514,13 +515,13 @@ Opts.Index = I.get(); auto Results = completions(R"cpp( - namespace ns { class No {}; } + namespace ns { class 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) { @@ -561,6 +562,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;