[clangd] Code completion uses Sema for NS-level things in the current file.

Summary:
To stay fast, it avoids deserializing anything outside the current file, by
disabling the LoadExternal code completion option added in r322377, when the
index is enabled.

Reviewers: hokein

Subscribers: klimek, ilya-biryukov, cfe-commits

Differential Revision: https://reviews.llvm.org/D41996

llvm-svn: 322387
This commit is contained in:
Sam McCall 2018-01-12 18:30:08 +00:00
parent 5e102eeee6
commit 3d139c527b
3 changed files with 47 additions and 7 deletions

View File

@ -642,8 +642,10 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
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;
}

View File

@ -20,6 +20,8 @@ std::unique_ptr<SymbolSlab> indexAST(ASTContext &Ctx,
std::shared_ptr<Preprocessor> PP,
llvm::ArrayRef<const Decl *> 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<SymbolCollector>(std::move(CollectorOpts));
Collector->setPreprocessor(std::move(PP));

View File

@ -57,6 +57,7 @@ using ::testing::Contains;
using ::testing::Each;
using ::testing::ElementsAre;
using ::testing::Not;
using ::testing::UnorderedElementsAre;
class IgnoreDiagnostics : public DiagnosticsConsumer {
void
@ -104,7 +105,7 @@ CompletionList completions(StringRef Text,
/*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 @@ TEST(CompletionTest, NoIndex) {
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 @@ TEST(CompletionTest, SimpleIndexBased) {
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 @@ TEST(CompletionTest, FullyQualifiedScope) {
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;