From 0320ce8916a815d10a0449f5581e0f3ca7183922 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 19 May 2020 15:21:50 +0200 Subject: [PATCH] [clangd] Add a flag to preserve type for recovery expression. Reviewers: sammccall Reviewed By: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D79938 --- clang-tools-extra/clangd/ClangdServer.cpp | 6 ++++-- clang-tools-extra/clangd/ClangdServer.h | 5 +++++ clang-tools-extra/clangd/CodeComplete.cpp | 1 + clang-tools-extra/clangd/Compiler.cpp | 4 +++- clang-tools-extra/clangd/Compiler.h | 1 + clang-tools-extra/clangd/tool/ClangdMain.cpp | 9 +++++++++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp | 13 +++++++++++++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp | 13 +++++++++++++ clang-tools-extra/clangd/unittests/TestTU.cpp | 1 + 9 files changed, 50 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 9231296..910c591 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -135,8 +135,9 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, : nullptr), GetClangTidyOptions(Opts.GetClangTidyOptions), SuggestMissingIncludes(Opts.SuggestMissingIncludes), - BuildRecoveryAST(Opts.BuildRecoveryAST), TweakFilter(Opts.TweakFilter), - WorkspaceRoot(Opts.WorkspaceRoot), + BuildRecoveryAST(Opts.BuildRecoveryAST), + PreserveRecoveryASTType(Opts.PreserveRecoveryASTType), + TweakFilter(Opts.TweakFilter), WorkspaceRoot(Opts.WorkspaceRoot), // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST // is parsed. @@ -194,6 +195,7 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents, Inputs.Opts = std::move(Opts); Inputs.Index = Index; Inputs.Opts.BuildRecoveryAST = BuildRecoveryAST; + Inputs.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; bool NewFile = WorkScheduler.update(File, Inputs, WantDiags); // If we loaded Foo.h, we want to make sure Foo.cpp is indexed. if (NewFile && BackgroundIdx) diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index 76fa64b..68344eb 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -120,6 +120,9 @@ public: /// If true, turn on the `-frecovery-ast` clang flag. bool BuildRecoveryAST = false; + /// If true, turn on the `-frecovery-ast-type` clang flag. + bool PreserveRecoveryASTType = false; + /// Clangd's workspace root. Relevant for "workspace" operations not bound /// to a particular file. /// FIXME: If not set, should use the current working directory. @@ -349,6 +352,8 @@ private: // If true, preserve expressions in AST for broken code. bool BuildRecoveryAST = false; + // If true, preserve the type for recovery AST. + bool PreserveRecoveryASTType = false; std::function TweakFilter; diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 03c1cb1..f2bdadb 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1069,6 +1069,7 @@ bool semaCodeComplete(std::unique_ptr Consumer, ParseInput.CompileCommand = Input.Command; ParseInput.FS = VFS; ParseInput.Contents = std::string(Input.Contents); + // FIXME: setup the recoveryAST and recoveryASTType in ParseInput properly. IgnoreDiagnostics IgnoreDiags; auto CI = buildCompilerInvocation(ParseInput, IgnoreDiags); diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index ee9b187..9eb86a4 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -84,8 +84,10 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, CI->getPreprocessorOpts().PCHWithHdrStopCreate = false; // Recovery expression currently only works for C++. - if (CI->getLangOpts()->CPlusPlus) + if (CI->getLangOpts()->CPlusPlus) { CI->getLangOpts()->RecoveryAST = Inputs.Opts.BuildRecoveryAST; + CI->getLangOpts()->RecoveryASTType = Inputs.Opts.PreserveRecoveryASTType; + } return CI; } diff --git a/clang-tools-extra/clangd/Compiler.h b/clang-tools-extra/clangd/Compiler.h index b7cc174..5c4cf39 100644 --- a/clang-tools-extra/clangd/Compiler.h +++ b/clang-tools-extra/clangd/Compiler.h @@ -39,6 +39,7 @@ struct ParseOptions { tidy::ClangTidyOptions ClangTidyOpts; bool SuggestMissingIncludes = false; bool BuildRecoveryAST = false; + bool PreserveRecoveryASTType = false; }; /// Information required to run clang, e.g. to parse AST or do code completion. diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index e59aecb..031f57f 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -289,6 +289,14 @@ opt RecoveryAST{ init(false), Hidden, }; +opt RecoveryASTType{ + "recovery-ast-type", + cat(Features), + desc("Preserve the type for recovery AST. Note that " + "this feature is experimental and may lead to crashes"), + init(false), + Hidden, +}; opt WorkerThreadsCount{ "j", @@ -641,6 +649,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.StaticIndex = StaticIdx.get(); Opts.AsyncThreadsCount = WorkerThreadsCount; Opts.BuildRecoveryAST = RecoveryAST; + Opts.PreserveRecoveryASTType = RecoveryASTType; clangd::CodeCompleteOptions CCOpts; CCOpts.IncludeIneligibleResults = IncludeIneligibleResults; diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 77b5c5a..d2b9661 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -753,6 +753,19 @@ TEST(CompletionTest, CompletionInPreamble) { EXPECT_THAT(Results, ElementsAre(Named("ifndef"))); } +// FIXME: enable it. +TEST(CompletionTest, DISABLED_CompletionRecoveryASTType) { + auto Results = completions(R"cpp( + struct S { int member; }; + S overloaded(int); + void foo() { + // No overload matches, but we have recovery-expr with the correct type. + overloaded().^ + })cpp") + .Completions; + EXPECT_THAT(Results, ElementsAre(Named("member"))); +} + TEST(CompletionTest, DynamicIndexIncludeInsertion) { MockFSProvider FS; MockCompilationDatabase CDB; diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 03cdc02..94d0402 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -158,6 +158,19 @@ TEST_F(TargetDeclTest, Recovery) { EXPECT_DECLS("UnresolvedLookupExpr", "int f()", "int f(int, int)"); } +TEST_F(TargetDeclTest, RecoveryType) { + Code = R"cpp( + // error-ok: testing behavior on broken code + struct S { int member; }; + S overloaded(int); + void foo() { + // No overload matches, but we have recovery-expr with the correct type. + overloaded().[[member]]; + } + )cpp"; + EXPECT_DECLS("MemberExpr", "int member"); +} + TEST_F(TargetDeclTest, UsingDecl) { Code = R"cpp( namespace foo { diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp index 8ff1120..6d9de48 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -57,6 +57,7 @@ ParseInputs TestTU::inputs() const { Inputs.FS = buildTestFS(Files); Inputs.Opts = ParseOptions(); Inputs.Opts.BuildRecoveryAST = true; + Inputs.Opts.PreserveRecoveryASTType = true; Inputs.Opts.ClangTidyOpts.Checks = ClangTidyChecks; Inputs.Opts.ClangTidyOpts.WarningsAsErrors = ClangTidyWarningsAsErrors; Inputs.Index = ExternalIndex; -- 2.7.4