From 0321b370f2db205b0a67c4881c2413d5cb2d41c4 Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Tue, 21 May 2019 13:40:31 +0000 Subject: [PATCH] [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 --- clang-tools-extra/clangd/ClangdServer.cpp | 10 +++++---- clang-tools-extra/clangd/CodeComplete.cpp | 7 ++++--- clang-tools-extra/clangd/CodeComplete.h | 17 ++++++++++----- clang-tools-extra/clangd/tool/ClangdMain.cpp | 21 ++++++++++++------- .../clangd/unittests/ClangdTests.cpp | 21 ++++++++++++------- 5 files changed, 49 insertions(+), 27 deletions(-) diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 22fb2aec8322..449c0c980991 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -200,10 +200,12 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, }; // We use a potentially-stale preamble because latency is critical here. - WorkScheduler.runWithPreamble("CodeComplete", File, - Opts.AllowFallback ? TUScheduler::StaleOrAbsent - : TUScheduler::Stale, - Bind(Task, File.str(), std::move(CB))); + WorkScheduler.runWithPreamble( + "CodeComplete", File, + (Opts.RunParser == CodeCompleteOptions::AlwaysParse) + ? TUScheduler::Stale + : TUScheduler::StaleOrAbsent, + Bind(Task, File.str(), std::move(CB))); } void ClangdServer::signatureHelp(PathRef File, Position Pos, diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 4789a8094c5d..7f811c31de5b 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1738,9 +1738,10 @@ codeComplete(PathRef FileName, const tooling::CompileCommand &Command, auto Flow = CodeCompleteFlow( FileName, Preamble ? Preamble->Includes : IncludeStructure(), SpecFuzzyFind, Opts); - return Preamble ? std::move(Flow).run( - {FileName, Command, Preamble, Contents, *Offset, VFS}) - : std::move(Flow).runWithoutSema(Contents, *Offset, VFS); + return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) + ? std::move(Flow).runWithoutSema(Contents, *Offset, VFS) + : std::move(Flow).run( + {FileName, Command, Preamble, Contents, *Offset, VFS}); } SignatureHelp signatureHelp(PathRef FileName, diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index 2dc7f22c14dd..58728285d96a 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -115,11 +115,18 @@ struct CodeCompleteOptions { /// Such completions can insert scope qualifiers. bool AllScopes = false; - /// Whether to allow falling back to code completion without compiling files - /// (using identifiers in the current file and symbol indexes), when file - /// cannot be built (e.g. missing compile command), or the build is not ready - /// (e.g. preamble is still being built). - bool AllowFallback = false; + /// Whether to use the clang parser, or fallback to text-based completion + /// (using identifiers in the current file and symbol indexes). + enum CodeCompletionParse { + /// Block until we can run the parser (e.g. preamble is built). + /// 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. diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 2285d5354f97..aca72eabf40d 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -256,13 +256,18 @@ static llvm::cl::opt ForceOffsetEncoding( "Offsets are in UTF-16 code units")), llvm::cl::init(OffsetEncoding::UnsupportedEncoding)); -static llvm::cl::opt AllowFallbackCompletion( - "allow-fallback-completion", - llvm::cl::desc( - "Allow falling back to code completion without compiling files (using " - "identifiers and symbol indexes), when file cannot be built or the " - "build is not ready."), - llvm::cl::init(false)); +static llvm::cl::opt + CodeCompletionParse( + "completion-parse", + llvm::cl::desc("Whether the clang-parser is used for code-completion"), + llvm::cl::values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always", + "Block until the parser can be used"), + 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 { @@ -475,7 +480,7 @@ int main(int argc, char *argv[]) { CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; CCOpts.AllScopes = AllScopesCompletion; - CCOpts.AllowFallback = AllowFallbackCompletion; + CCOpts.RunParser = CodeCompletionParse; RealFileSystemProvider FSProvider; // Initialize and run ClangdLSPServer. diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index 16d1ef26bea5..ac4ff6ed077a 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -9,6 +9,7 @@ #include "Annotations.h" #include "ClangdLSPServer.h" #include "ClangdServer.h" +#include "CodeComplete.h" #include "GlobalCompilationDatabase.h" #include "Matchers.h" #include "SyncAPI.h" @@ -1072,7 +1073,7 @@ TEST_F(ClangdVFSTest, FallbackWhenPreambleIsNotReady) { FS.Files[FooCpp] = FooCpp; auto Opts = clangd::CodeCompleteOptions(); - Opts.AllowFallback = true; + Opts.RunParser = CodeCompleteOptions::ParseIfReady; // This will make compile command broken and preamble absent. CDB.ExtraClangFlags = {"yolo.cc"}; @@ -1089,11 +1090,17 @@ TEST_F(ClangdVFSTest, FallbackWhenPreambleIsNotReady) { CDB.ExtraClangFlags = {"-std=c++11"}; Server.addDocument(FooCpp, Code.code()); ASSERT_TRUE(Server.blockUntilIdleForTest()); - EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Code.point(), - clangd::CodeCompleteOptions())) - .Completions, - ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"), - Field(&CodeCompletion::Scope, "ns::")))); + EXPECT_THAT( + cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)).Completions, + ElementsAre(AllOf(Field(&CodeCompletion::Name, "xyz"), + 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) { @@ -1140,7 +1147,7 @@ TEST_F(ClangdVFSTest, FallbackWhenWaitingForCompileCommand) { // hasn't been scheduled. std::this_thread::sleep_for(std::chrono::milliseconds(10)); auto Opts = clangd::CodeCompleteOptions(); - Opts.AllowFallback = true; + Opts.RunParser = CodeCompleteOptions::ParseIfReady; auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)); EXPECT_EQ(Res.Context, CodeCompletionContext::CCC_Recovery);