https://github.com/petr-polezhaev updated https://github.com/llvm/llvm-project/pull/122606
>From 4db81c715375422f31fd036e7ac308c3c2a579fd Mon Sep 17 00:00:00 2001 From: Petr Polezhaev <petr.polezh...@ratigorsk-12.ru> Date: Sat, 11 Jan 2025 21:21:16 +0300 Subject: [PATCH] [clangd] Support .clangd command line modifications in ScanningAllProjectModules --- .../clangd/GlobalCompilationDatabase.cpp | 10 +++++ .../clangd/GlobalCompilationDatabase.h | 3 ++ clang-tools-extra/clangd/ProjectModules.h | 7 ++++ .../clangd/ScanningProjectModules.cpp | 38 +++++++++++------- .../unittests/PrerequisiteModulesTest.cpp | 40 ++++++++++++++++++- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 71e97ac4efd673..2b1da4be5c1bd6 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -830,6 +830,16 @@ bool OverlayCDB::setCompileCommand(PathRef File, return true; } +std::unique_ptr<ProjectModules> +OverlayCDB::getProjectModules(PathRef File) const { + auto MDB = DelegatingCDB::getProjectModules(File); + MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command, + PathRef CommandPath) { + Mangler(Command, CommandPath); + }); + return std::move(MDB); +} + DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base) : Base(Base) { if (Base) diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h index f8349c6efecb01..1d636d73664bee 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h @@ -209,6 +209,9 @@ class OverlayCDB : public DelegatingCDB { setCompileCommand(PathRef File, std::optional<tooling::CompileCommand> CompilationCommand); + std::unique_ptr<ProjectModules> + getProjectModules(PathRef File) const override; + private: mutable std::mutex Mutex; llvm::StringMap<tooling::CompileCommand> Commands; /* GUARDED_BY(Mut) */ diff --git a/clang-tools-extra/clangd/ProjectModules.h b/clang-tools-extra/clangd/ProjectModules.h index 3b9b564a87da01..48d52ac9deb893 100644 --- a/clang-tools-extra/clangd/ProjectModules.h +++ b/clang-tools-extra/clangd/ProjectModules.h @@ -9,8 +9,10 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROJECTMODULES_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROJECTMODULES_H +#include "support/Function.h" #include "support/Path.h" #include "support/ThreadsafeFS.h" +#include "clang/Tooling/CompilationDatabase.h" #include <memory> @@ -36,11 +38,16 @@ namespace clangd { /// `<primary-module-name>[:partition-name]`. So module names covers partitions. class ProjectModules { public: + using CommandMangler = + llvm::unique_function<void(tooling::CompileCommand &, PathRef) const>; + virtual std::vector<std::string> getRequiredModules(PathRef File) = 0; virtual PathRef getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSrcFile = PathRef()) = 0; + virtual void setCommandMangler(CommandMangler Mangler) {} + virtual ~ProjectModules() = default; }; diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp index 92f75ef7d5c25a..e4dc11c1c28958 100644 --- a/clang-tools-extra/clangd/ScanningProjectModules.cpp +++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp @@ -48,7 +48,8 @@ class ModuleDependencyScanner { }; /// Scanning the single file specified by \param FilePath. - std::optional<ModuleDependencyInfo> scan(PathRef FilePath); + std::optional<ModuleDependencyInfo> + scan(PathRef FilePath, const ProjectModules::CommandMangler &Mangler); /// Scanning every source file in the current project to get the /// <module-name> to <module-unit-source> map. @@ -57,7 +58,7 @@ class ModuleDependencyScanner { /// a global module dependency scanner to monitor every file. Or we /// can simply require the build systems (or even the end users) /// to provide the map. - void globalScan(); + void globalScan(const ProjectModules::CommandMangler &Mangler); /// Get the source file from the module name. Note that the language /// guarantees all the module names are unique in a valid program. @@ -69,7 +70,9 @@ class ModuleDependencyScanner { /// Return the direct required modules. Indirect required modules are not /// included. - std::vector<std::string> getRequiredModules(PathRef File); + std::vector<std::string> + getRequiredModules(PathRef File, + const ProjectModules::CommandMangler &Mangler); private: std::shared_ptr<const clang::tooling::CompilationDatabase> CDB; @@ -87,7 +90,8 @@ class ModuleDependencyScanner { }; std::optional<ModuleDependencyScanner::ModuleDependencyInfo> -ModuleDependencyScanner::scan(PathRef FilePath) { +ModuleDependencyScanner::scan(PathRef FilePath, + const ProjectModules::CommandMangler &Mangler) { auto Candidates = CDB->getCompileCommands(FilePath); if (Candidates.empty()) return std::nullopt; @@ -97,10 +101,8 @@ ModuleDependencyScanner::scan(PathRef FilePath) { // DirectoryBasedGlobalCompilationDatabase::getCompileCommand. tooling::CompileCommand Cmd = std::move(Candidates.front()); - static int StaticForMainAddr; // Just an address in this process. - Cmd.CommandLine.push_back("-resource-dir=" + - CompilerInvocation::GetResourcesPath( - "clangd", (void *)&StaticForMainAddr)); + if (Mangler) + Mangler(Cmd, FilePath); using namespace clang::tooling::dependencies; @@ -130,9 +132,10 @@ ModuleDependencyScanner::scan(PathRef FilePath) { return Result; } -void ModuleDependencyScanner::globalScan() { +void ModuleDependencyScanner::globalScan( + const ProjectModules::CommandMangler &Mangler) { for (auto &File : CDB->getAllFiles()) - scan(File); + scan(File, Mangler); GlobalScanned = true; } @@ -150,9 +153,9 @@ PathRef ModuleDependencyScanner::getSourceForModuleName( return {}; } -std::vector<std::string> -ModuleDependencyScanner::getRequiredModules(PathRef File) { - auto ScanningResult = scan(File); +std::vector<std::string> ModuleDependencyScanner::getRequiredModules( + PathRef File, const ProjectModules::CommandMangler &Mangler) { + auto ScanningResult = scan(File, Mangler); if (!ScanningResult) return {}; @@ -177,7 +180,11 @@ class ScanningAllProjectModules : public ProjectModules { ~ScanningAllProjectModules() override = default; std::vector<std::string> getRequiredModules(PathRef File) override { - return Scanner.getRequiredModules(File); + return Scanner.getRequiredModules(File, Mangler); + } + + void setCommandMangler(CommandMangler Mangler) override { + this->Mangler = std::move(Mangler); } /// RequiredSourceFile is not used intentionally. See the comments of @@ -185,12 +192,13 @@ class ScanningAllProjectModules : public ProjectModules { PathRef getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile = PathRef()) override { - Scanner.globalScan(); + Scanner.globalScan(Mangler); return Scanner.getSourceForModuleName(ModuleName); } private: ModuleDependencyScanner Scanner; + CommandMangler Mangler; }; std::unique_ptr<ProjectModules> scanningProjectModules( diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp index 1bb8e19cce23e0..7535582226a60c 100644 --- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp +++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp @@ -18,6 +18,7 @@ #include "Compiler.h" #include "TestTU.h" #include "support/ThreadsafeFS.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include "gmock/gmock.h" @@ -191,6 +192,41 @@ export module M; EXPECT_TRUE(MInfo->canReuse(*Invocation, FS.view(TestDir))); } +TEST_F(PrerequisiteModulesTests, ModuleWithArgumentPatch) { + MockDirectoryCompilationDatabase CDB(TestDir, FS); + + CDB.ExtraClangFlags.push_back("-invalid-unknown-flag"); + + CDB.addFile("Dep.cppm", R"cpp( +export module Dep; + )cpp"); + + CDB.addFile("M.cppm", R"cpp( +export module M; +import Dep; + )cpp"); + + // An invalid flag will break the module compilation and the + // getRequiredModules would return an empty array + auto ProjectModules = CDB.getProjectModules(getFullPath("M.cppm")); + EXPECT_TRUE( + ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty()); + + // Set the mangler to filter out the invalid flag + ProjectModules->setCommandMangler( + [](tooling::CompileCommand &Command, PathRef) { + auto const It = + std::find(Command.CommandLine.begin(), Command.CommandLine.end(), + "-invalid-unknown-flag"); + Command.CommandLine.erase(It); + }); + + // And now it returns a non-empty list of required modules since the + // compilation succeeded + EXPECT_FALSE( + ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty()); +} + TEST_F(PrerequisiteModulesTests, ModuleWithDepTest) { MockDirectoryCompilationDatabase CDB(TestDir, FS); @@ -435,7 +471,7 @@ void func() { /*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()); @@ -474,7 +510,7 @@ void func() { /*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()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits