https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/110083
>From e35e600159c99736de7d2bc735c738002f592988 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Thu, 26 Sep 2024 13:43:51 +0800 Subject: [PATCH 1/5] [clangd] [C++20] [Modules] Support code complete for C++20 modules --- clang-tools-extra/clangd/CodeComplete.cpp | 18 ++++++--- clang-tools-extra/clangd/CodeComplete.h | 2 +- .../unittests/PrerequisiteModulesTest.cpp | 40 +++++++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 89eee392837af4..f6f0d9a1be3c37 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -892,8 +892,9 @@ static bool isExcludedMember(const NamedDecl &D) { // within the callback. struct CompletionRecorder : public CodeCompleteConsumer { CompletionRecorder(const CodeCompleteOptions &Opts, + bool ForceLoadExternal, llvm::unique_function<void()> ResultsCallback) - : CodeCompleteConsumer(Opts.getClangCompleteOpts()), + : CodeCompleteConsumer(Opts.getClangCompleteOpts(ForceLoadExternal)), CCContext(CodeCompletionContext::CCC_Other), Opts(Opts), CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()), CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) { @@ -1409,6 +1410,9 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble; Clang->setCodeCompletionConsumer(Consumer.release()); + if (Input.Preamble.RequiredModules) + Input.Preamble.RequiredModules->adjustHeaderSearchOptions(Clang->getHeaderSearchOpts()); + SyntaxOnlyAction Action; if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) { log("BeginSourceFile() failed when running codeComplete for {0}", @@ -1629,11 +1633,15 @@ class CodeCompleteFlow { SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq); } + // FIXME: If we're using C++20 modules, force the lookup process to load external decls, + // since currently the index doesn't support C++20 modules. + bool ForceLoadExternal = (bool)SemaCCInput.Preamble.RequiredModules; + // We run Sema code completion first. It builds an AST and calculates: // - completion results based on the AST. // - partial identifier and context. We need these for the index query. CodeCompleteResult Output; - auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() { + auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, ForceLoadExternal, [&]() { assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); @@ -1691,7 +1699,7 @@ class CodeCompleteFlow { Recorder = RecorderOwner.get(); - semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(), + semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(ForceLoadExternal), SemaCCInput, &Includes); logResults(Output, Tracer); return Output; @@ -2108,7 +2116,7 @@ class CodeCompleteFlow { } // namespace -clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { +clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts(bool ForceLoadExternal) const { clang::CodeCompleteOptions Result; Result.IncludeCodePatterns = EnableSnippets; Result.IncludeMacros = true; @@ -2122,7 +2130,7 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { // 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; + Result.LoadExternal = ForceLoadExternal || !Index; Result.IncludeFixIts = IncludeFixIts; return Result; diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index a7c1ae95dcbf49..336e84f0a7724c 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -41,7 +41,7 @@ struct CodeCompletion; struct CodeCompleteOptions { /// Returns options that can be passed to clang's completion engine. - clang::CodeCompleteOptions getClangCompleteOpts() const; + clang::CodeCompleteOptions getClangCompleteOpts(bool ForceLoadExternal) const; /// When true, completion items will contain expandable code snippets in /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp index 7bbb95c8b8d67f..f1cdf9e899f4d8 100644 --- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp +++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp @@ -402,6 +402,46 @@ import A; EXPECT_TRUE(D.isFromASTFile()); } +// An end to end test for code complete in modules +TEST_F(PrerequisiteModulesTests, CodeCompleteTest) { + MockDirectoryCompilationDatabase CDB(TestDir, FS); + + CDB.addFile("A.cppm", R"cpp( +export module A; +export void printA(); + )cpp"); + + llvm::StringLiteral UserContents = R"cpp( +import A; +void func() { + print^ +} +)cpp"; + + CDB.addFile("Use.cpp", UserContents); + Annotations Test(UserContents); + + ModulesBuilder Builder(CDB); + + ParseInputs Use = getInputs("Use.cpp", CDB); + Use.ModulesManager = &Builder; + + std::unique_ptr<CompilerInvocation> CI = + buildCompilerInvocation(Use, DiagConsumer); + EXPECT_TRUE(CI); + + auto Preamble = + buildPreamble(getFullPath("Use.cpp"), *CI, Use, /*InMemory=*/true, + /*Callback=*/nullptr); + EXPECT_TRUE(Preamble); + EXPECT_TRUE(Preamble->RequiredModules); + + auto Result = codeComplete(getFullPath("Use.cpp"), Test.point(), + Preamble.get(), Use, {}); + EXPECT_FALSE(Result.Completions.empty()); + EXPECT_EQ(Result.Completions[0].Name, "printA"); +} + } // namespace } // namespace clang::clangd >From d07a5435fcc0d405bc1b5ecacbeaf313501c7c96 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Fri, 27 Sep 2024 10:21:39 +0800 Subject: [PATCH 2/5] Update --- .../unittests/PrerequisiteModulesTest.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp index f1cdf9e899f4d8..691a93e7acd0af 100644 --- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp +++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp @@ -442,6 +442,46 @@ void func() { EXPECT_EQ(Result.Completions[0].Name, "printA"); } +TEST_F(PrerequisiteModulesTests, SignatureHelpTest) { + MockDirectoryCompilationDatabase CDB(TestDir, FS); + + CDB.addFile("A.cppm", R"cpp( +export module A; +export void printA(int a); + )cpp"); + + llvm::StringLiteral UserContents = R"cpp( +import A; +void func() { + printA(^); +} +)cpp"; + + CDB.addFile("Use.cpp", UserContents); + Annotations Test(UserContents); + + ModulesBuilder Builder(CDB); + + ParseInputs Use = getInputs("Use.cpp", CDB); + Use.ModulesManager = &Builder; + + std::unique_ptr<CompilerInvocation> CI = + buildCompilerInvocation(Use, DiagConsumer); + EXPECT_TRUE(CI); + + auto Preamble = + buildPreamble(getFullPath("Use.cpp"), *CI, Use, /*InMemory=*/true, + /*Callback=*/nullptr); + EXPECT_TRUE(Preamble); + EXPECT_TRUE(Preamble->RequiredModules); + + auto Result = signatureHelp(getFullPath("Use.cpp"), Test.point(), + *Preamble.get(), Use, MarkupKind::PlainText); + EXPECT_FALSE(Result.signatures.empty()); + EXPECT_EQ(Result.signatures[0].label, "printA(int a) -> void"); + EXPECT_EQ(Result.signatures[0].parameters[0].labelString, "int a"); +} + } // namespace } // namespace clang::clangd >From c1755db71dff183f5000e6ed0592889a1a2deff8 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Sun, 29 Sep 2024 10:09:59 +0800 Subject: [PATCH 3/5] update --- clang-tools-extra/clangd/CodeComplete.cpp | 18 ++++++++---------- clang-tools-extra/clangd/CodeComplete.h | 5 ++++- clang-tools-extra/clangd/tool/ClangdMain.cpp | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index f6f0d9a1be3c37..5553a33338bb60 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -892,9 +892,8 @@ static bool isExcludedMember(const NamedDecl &D) { // within the callback. struct CompletionRecorder : public CodeCompleteConsumer { CompletionRecorder(const CodeCompleteOptions &Opts, - bool ForceLoadExternal, llvm::unique_function<void()> ResultsCallback) - : CodeCompleteConsumer(Opts.getClangCompleteOpts(ForceLoadExternal)), + : CodeCompleteConsumer(Opts.getClangCompleteOpts()), CCContext(CodeCompletionContext::CCC_Other), Opts(Opts), CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()), CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) { @@ -1633,15 +1632,11 @@ class CodeCompleteFlow { SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq); } - // FIXME: If we're using C++20 modules, force the lookup process to load external decls, - // since currently the index doesn't support C++20 modules. - bool ForceLoadExternal = (bool)SemaCCInput.Preamble.RequiredModules; - // We run Sema code completion first. It builds an AST and calculates: // - completion results based on the AST. // - partial identifier and context. We need these for the index query. CodeCompleteResult Output; - auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, ForceLoadExternal, [&]() { + auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() { assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); @@ -1699,7 +1694,7 @@ class CodeCompleteFlow { Recorder = RecorderOwner.get(); - semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(ForceLoadExternal), + semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(), SemaCCInput, &Includes); logResults(Output, Tracer); return Output; @@ -2116,7 +2111,7 @@ class CodeCompleteFlow { } // namespace -clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts(bool ForceLoadExternal) const { +clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { clang::CodeCompleteOptions Result; Result.IncludeCodePatterns = EnableSnippets; Result.IncludeMacros = true; @@ -2130,7 +2125,10 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts(bool ForceL // 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 = ForceLoadExternal || !Index; + // + // FIXME: If we're using C++20 modules, force the lookup process to load external decls, + // since currently the index doesn't support C++20 modules. + Result.LoadExternal = ExperimentalModulesSupport || !Index; Result.IncludeFixIts = IncludeFixIts; return Result; diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index 336e84f0a7724c..f78473e1189194 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -41,7 +41,7 @@ struct CodeCompletion; struct CodeCompleteOptions { /// Returns options that can be passed to clang's completion engine. - clang::CodeCompleteOptions getClangCompleteOpts(bool ForceLoadExternal) const; + clang::CodeCompleteOptions getClangCompleteOpts() const; /// When true, completion items will contain expandable code snippets in /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int @@ -52,6 +52,9 @@ struct CodeCompleteOptions { /// For example, private members are usually inaccessible. bool IncludeIneligibleResults = false; + /// Whether the experimental modules support are enabled. + bool ExperimentalModulesSupport = false; + /// Combine overloads into a single completion item where possible. /// If none, the implementation may choose an appropriate behavior. /// (In practice, ClangdLSPServer enables bundling if the client claims diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 3a5449ac8c7994..9aa3c8855ed526 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -919,6 +919,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.CodeComplete.EnableFunctionArgSnippets = EnableFunctionArgSnippets; Opts.CodeComplete.RunParser = CodeCompletionParse; Opts.CodeComplete.RankingModel = RankingModel; + Opts.CodeComplete.ExperimentalModulesSupport = ExperimentalModulesSupport; RealThreadsafeFS TFS; std::vector<std::unique_ptr<config::Provider>> ProviderStack; >From b2037977a07566817f4ccd9e2adc57a142aebfdb Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Mon, 30 Sep 2024 11:37:49 +0800 Subject: [PATCH 4/5] addres cocmments --- clang-tools-extra/clangd/CodeComplete.cpp | 5 +---- clang-tools-extra/clangd/CodeComplete.h | 6 ++++-- clang-tools-extra/clangd/tool/ClangdMain.cpp | 4 +++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 5553a33338bb60..6711eb7dc10f82 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -2125,10 +2125,7 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { // 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. - // - // FIXME: If we're using C++20 modules, force the lookup process to load external decls, - // since currently the index doesn't support C++20 modules. - Result.LoadExternal = ExperimentalModulesSupport || !Index; + Result.LoadExternal = ForceLoadPreamble || !Index; Result.IncludeFixIts = IncludeFixIts; return Result; diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index f78473e1189194..8dd27469448cf7 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -52,8 +52,10 @@ struct CodeCompleteOptions { /// For example, private members are usually inaccessible. bool IncludeIneligibleResults = false; - /// Whether the experimental modules support are enabled. - bool ExperimentalModulesSupport = false; + /// Force sema to load decls from preamble even if an index is provided. + /// This is helpful for cases the index can't provide symbols, e.g., the + /// unsupported yet modules. + bool ForceLoadPreamble = false; /// Combine overloads into a single completion item where possible. /// If none, the implementation may choose an appropriate behavior. diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 9aa3c8855ed526..9487de1fb3fcd7 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -919,7 +919,9 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.CodeComplete.EnableFunctionArgSnippets = EnableFunctionArgSnippets; Opts.CodeComplete.RunParser = CodeCompletionParse; Opts.CodeComplete.RankingModel = RankingModel; - Opts.CodeComplete.ExperimentalModulesSupport = ExperimentalModulesSupport; + // FIXME: If we're using C++20 modules, force the lookup process to load external decls, + // since currently the index doesn't support C++20 modules. + Opts.CodeComplete.ForceLoadPreamble = ExperimentalModulesSupport; RealThreadsafeFS TFS; std::vector<std::unique_ptr<config::Provider>> ProviderStack; >From a21c0148e920be41ca4a870b29a21ccf6ef1031d Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Mon, 30 Sep 2024 11:38:18 +0800 Subject: [PATCH 5/5] update --- clang-tools-extra/clangd/tool/ClangdMain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 9487de1fb3fcd7..1b669c50fa31a9 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -919,8 +919,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.CodeComplete.EnableFunctionArgSnippets = EnableFunctionArgSnippets; Opts.CodeComplete.RunParser = CodeCompletionParse; Opts.CodeComplete.RankingModel = RankingModel; - // FIXME: If we're using C++20 modules, force the lookup process to load external decls, - // since currently the index doesn't support C++20 modules. + // FIXME: If we're using C++20 modules, force the lookup process to load + // external decls, since currently the index doesn't support C++20 modules. Opts.CodeComplete.ForceLoadPreamble = ExperimentalModulesSupport; RealThreadsafeFS TFS; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits