[clangd] Turn no-parse-completion on by when preamble isn't ready. Add flag to force it.

Reviewers: kadircet

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits

Tags: #clang

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

llvm-svn: 361258
This commit is contained in:
Sam McCall 2019-05-21 13:40:31 +00:00
parent 8fa970c2d8
commit 0321b370f2
5 changed files with 49 additions and 27 deletions

View File

@ -200,10 +200,12 @@ void ClangdServer::codeComplete(PathRef File, Position Pos,
}; };
// We use a potentially-stale preamble because latency is critical here. // We use a potentially-stale preamble because latency is critical here.
WorkScheduler.runWithPreamble("CodeComplete", File, WorkScheduler.runWithPreamble(
Opts.AllowFallback ? TUScheduler::StaleOrAbsent "CodeComplete", File,
: TUScheduler::Stale, (Opts.RunParser == CodeCompleteOptions::AlwaysParse)
Bind(Task, File.str(), std::move(CB))); ? TUScheduler::Stale
: TUScheduler::StaleOrAbsent,
Bind(Task, File.str(), std::move(CB)));
} }
void ClangdServer::signatureHelp(PathRef File, Position Pos, void ClangdServer::signatureHelp(PathRef File, Position Pos,

View File

@ -1738,9 +1738,10 @@ codeComplete(PathRef FileName, const tooling::CompileCommand &Command,
auto Flow = CodeCompleteFlow( auto Flow = CodeCompleteFlow(
FileName, Preamble ? Preamble->Includes : IncludeStructure(), FileName, Preamble ? Preamble->Includes : IncludeStructure(),
SpecFuzzyFind, Opts); SpecFuzzyFind, Opts);
return Preamble ? std::move(Flow).run( return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse)
{FileName, Command, Preamble, Contents, *Offset, VFS}) ? std::move(Flow).runWithoutSema(Contents, *Offset, VFS)
: std::move(Flow).runWithoutSema(Contents, *Offset, VFS); : std::move(Flow).run(
{FileName, Command, Preamble, Contents, *Offset, VFS});
} }
SignatureHelp signatureHelp(PathRef FileName, SignatureHelp signatureHelp(PathRef FileName,

View File

@ -115,11 +115,18 @@ struct CodeCompleteOptions {
/// Such completions can insert scope qualifiers. /// Such completions can insert scope qualifiers.
bool AllScopes = false; bool AllScopes = false;
/// Whether to allow falling back to code completion without compiling files /// Whether to use the clang parser, or fallback to text-based completion
/// (using identifiers in the current file and symbol indexes), when file /// (using identifiers in the current file and symbol indexes).
/// cannot be built (e.g. missing compile command), or the build is not ready enum CodeCompletionParse {
/// (e.g. preamble is still being built). /// Block until we can run the parser (e.g. preamble is built).
bool AllowFallback = false; /// Return an error if this fails.
AlwaysParse,
/// Run the parser if inputs (preamble) are ready.
/// Otherwise, use text-based completion.
ParseIfReady,
/// Always use text-based completion.
NeverParse,
} RunParser = ParseIfReady;
}; };
// Semi-structured representation of a code-complete suggestion for our C++ API. // Semi-structured representation of a code-complete suggestion for our C++ API.

View File

@ -256,13 +256,18 @@ static llvm::cl::opt<OffsetEncoding> ForceOffsetEncoding(
"Offsets are in UTF-16 code units")), "Offsets are in UTF-16 code units")),
llvm::cl::init(OffsetEncoding::UnsupportedEncoding)); llvm::cl::init(OffsetEncoding::UnsupportedEncoding));
static llvm::cl::opt<bool> AllowFallbackCompletion( static llvm::cl::opt<CodeCompleteOptions::CodeCompletionParse>
"allow-fallback-completion", CodeCompletionParse(
llvm::cl::desc( "completion-parse",
"Allow falling back to code completion without compiling files (using " llvm::cl::desc("Whether the clang-parser is used for code-completion"),
"identifiers and symbol indexes), when file cannot be built or the " llvm::cl::values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always",
"build is not ready."), "Block until the parser can be used"),
llvm::cl::init(false)); clEnumValN(CodeCompleteOptions::ParseIfReady, "auto",
"Use text-based completion if the parser "
"is not ready"),
clEnumValN(CodeCompleteOptions::NeverParse, "never",
"Always used text-based completion")),
llvm::cl::init(CodeCompleteOptions().RunParser), llvm::cl::Hidden);
namespace { namespace {
@ -475,7 +480,7 @@ int main(int argc, char *argv[]) {
CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; CCOpts.SpeculativeIndexRequest = Opts.StaticIndex;
CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets;
CCOpts.AllScopes = AllScopesCompletion; CCOpts.AllScopes = AllScopesCompletion;
CCOpts.AllowFallback = AllowFallbackCompletion; CCOpts.RunParser = CodeCompletionParse;
RealFileSystemProvider FSProvider; RealFileSystemProvider FSProvider;
// Initialize and run ClangdLSPServer. // Initialize and run ClangdLSPServer.

View File

@ -9,6 +9,7 @@
#include "Annotations.h" #include "Annotations.h"
#include "ClangdLSPServer.h" #include "ClangdLSPServer.h"
#include "ClangdServer.h" #include "ClangdServer.h"
#include "CodeComplete.h"
#include "GlobalCompilationDatabase.h" #include "GlobalCompilationDatabase.h"
#include "Matchers.h" #include "Matchers.h"
#include "SyncAPI.h" #include "SyncAPI.h"
@ -1072,7 +1073,7 @@ TEST_F(ClangdVFSTest, FallbackWhenPreambleIsNotReady) {
FS.Files[FooCpp] = FooCpp; FS.Files[FooCpp] = FooCpp;
auto Opts = clangd::CodeCompleteOptions(); auto Opts = clangd::CodeCompleteOptions();
Opts.AllowFallback = true; Opts.RunParser = CodeCompleteOptions::ParseIfReady;
// This will make compile command broken and preamble absent. // This will make compile command broken and preamble absent.
CDB.ExtraClangFlags = {"yolo.cc"}; CDB.ExtraClangFlags = {"yolo.cc"};
@ -1089,11 +1090,17 @@ TEST_F(ClangdVFSTest, FallbackWhenPreambleIsNotReady) {
CDB.ExtraClangFlags = {"-std=c++11"}; CDB.ExtraClangFlags = {"-std=c++11"};
Server.addDocument(FooCpp, Code.code()); Server.addDocument(FooCpp, Code.code());
ASSERT_TRUE(Server.blockUntilIdleForTest()); ASSERT_TRUE(Server.blockUntilIdleForTest());
EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Code.point(), EXPECT_THAT(
clangd::CodeCompleteOptions())) cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)).Completions,
.Completions, ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"), Field(&CodeCompletion::Scope, "ns::"))));
Field(&CodeCompletion::Scope, "ns::"))));
// Now force identifier-based completion.
Opts.RunParser = CodeCompleteOptions::NeverParse;
EXPECT_THAT(
cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)).Completions,
ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"),
Field(&CodeCompletion::Scope, ""))));
} }
TEST_F(ClangdVFSTest, FallbackWhenWaitingForCompileCommand) { TEST_F(ClangdVFSTest, FallbackWhenWaitingForCompileCommand) {
@ -1140,7 +1147,7 @@ TEST_F(ClangdVFSTest, FallbackWhenWaitingForCompileCommand) {
// hasn't been scheduled. // hasn't been scheduled.
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
auto Opts = clangd::CodeCompleteOptions(); auto Opts = clangd::CodeCompleteOptions();
Opts.AllowFallback = true; Opts.RunParser = CodeCompleteOptions::ParseIfReady;
auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)); auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts));
EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery); EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery);