DmitryPolukhin created this revision. DmitryPolukhin added reviewers: kadircet, nridge, sammccall, ilya-biryukov. DmitryPolukhin added a project: clang-tools-extra. Herald added a subscriber: arphaman. Herald added a project: All. DmitryPolukhin requested review of this revision. Herald added a subscriber: MaskRay.
Now clangd only interpolates CDBs loaded from disk and doesn't make any interpolation for CDBs pushed via LSP protocol. This diff add the same extrapolation logic as for loaded from disk. Test Plan: check-clangd Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D148663 Files: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/GlobalCompilationDatabase.cpp clang-tools-extra/clangd/GlobalCompilationDatabase.h clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
Index: clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp +++ clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp @@ -95,10 +95,14 @@ CDB.setCompileCommand(testPath("foo.cc"), Override); EXPECT_THAT(CDB.getCompileCommand(testPath("foo.cc"))->CommandLine, Contains("-DA=3")); - EXPECT_EQ(CDB.getCompileCommand(testPath("missing.cc")), std::nullopt); - CDB.setCompileCommand(testPath("missing.cc"), Override); + // Expect interpolation from foo.cc EXPECT_THAT(CDB.getCompileCommand(testPath("missing.cc"))->CommandLine, Contains("-DA=3")); + // Check that explicit override replaces interpolation + Override = cmd(testPath("missing.cc"), "-DA=4"); + CDB.setCompileCommand(testPath("missing.cc"), Override); + EXPECT_THAT(CDB.getCompileCommand(testPath("missing.cc"))->CommandLine, + Contains("-DA=4")); } TEST_F(OverlayCDBTest, GetFallbackCommand) { Index: clang-tools-extra/clangd/GlobalCompilationDatabase.h =================================================================== --- clang-tools-extra/clangd/GlobalCompilationDatabase.h +++ clang-tools-extra/clangd/GlobalCompilationDatabase.h @@ -17,6 +17,7 @@ #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include <memory> #include <mutex> #include <optional> @@ -189,14 +190,19 @@ getCompileCommand(PathRef File) const override; tooling::CompileCommand getFallbackCommand(PathRef File) const override; - /// Sets or clears the compilation command for a particular file. - void - setCompileCommand(PathRef File, - std::optional<tooling::CompileCommand> CompilationCommand); + /// Sets compilation commands and return updated files. + llvm::StringSet<> setCompileCommands( + llvm::StringMap<std::optional<tooling::CompileCommand>> Commands); + + /// Legacy inefficient implementation that inserts one file at a time + /// that is implemented as a wrapper on top of setCompileCommands above. + void setCompileCommand(PathRef File, + std::optional<tooling::CompileCommand> Cmd); private: mutable std::mutex Mutex; llvm::StringMap<tooling::CompileCommand> Commands; /* GUARDED_BY(Mut) */ + std::unique_ptr<tooling::CompilationDatabase> CDB; /* GUARDED_BY(Mut) */ CommandMangler Mangler; std::vector<std::string> FallbackFlags; }; Index: clang-tools-extra/clangd/GlobalCompilationDatabase.cpp =================================================================== --- clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -729,6 +729,35 @@ return Res->PI; } +// Helper class that exposes CDB pushed via LSP protocol as +// tooling::CompilationDatabase for interpolation. +class InMemoryCompilationDatabase : public tooling::CompilationDatabase { +public: + InMemoryCompilationDatabase( + llvm::StringMap<tooling::CompileCommand> &Commands) + : Commands(Commands) {} + + std::vector<tooling::CompileCommand> + getCompileCommands(StringRef FilePath) const override { + auto It = Commands.find(removeDots(FilePath)); + if (It != Commands.end()) + return {It->second}; + return {}; + } + + std::vector<std::string> getAllFiles() const override { + std::vector<std::string> Res; + Res.reserve(Commands.size()); + for (const auto &S : Commands.keys()) + Res.push_back(S.str()); + return Res; + } + +private: + // Use reference to OverlayCDB::Commands to avoid copies. + llvm::StringMap<tooling::CompileCommand> &Commands; +}; + OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base, std::vector<std::string> FallbackFlags, CommandMangler Mangler) @@ -740,9 +769,11 @@ std::optional<tooling::CompileCommand> Cmd; { std::lock_guard<std::mutex> Lock(Mutex); - auto It = Commands.find(removeDots(File)); - if (It != Commands.end()) - Cmd = It->second; + if (CDB) { + auto Candidates = CDB->getCompileCommands(File); + if (!Candidates.empty()) + Cmd = std::move(Candidates.front()); + } } if (!Cmd) Cmd = DelegatingCDB::getCompileCommand(File); @@ -763,20 +794,36 @@ return Cmd; } -void OverlayCDB::setCompileCommand(PathRef File, - std::optional<tooling::CompileCommand> Cmd) { - // We store a canonical version internally to prevent mismatches between set - // and get compile commands. Also it assures clients listening to broadcasts - // doesn't receive different names for the same file. - std::string CanonPath = removeDots(File); +llvm::StringSet<> OverlayCDB::setCompileCommands( + llvm::StringMap<std::optional<tooling::CompileCommand>> NewCommands) { + llvm::StringSet<> ModifiedFiles; { std::unique_lock<std::mutex> Lock(Mutex); - if (Cmd) - Commands[CanonPath] = std::move(*Cmd); - else - Commands.erase(CanonPath); + for (auto &E : NewCommands) { + // We store a canonical version internally to prevent mismatches between + // set and get compile commands. Also it assures clients listening to + // broadcasts doesn't receive different names for the same file. + std::string CanonPath = removeDots(E.getKey()); + if (E.getValue()) + Commands[CanonPath] = std::move(*E.getValue()); + else + Commands.erase(CanonPath); + ModifiedFiles.insert(CanonPath); + } + CDB = tooling::inferMissingCompileCommands( + std::unique_ptr<tooling::CompilationDatabase>( + new InMemoryCompilationDatabase(Commands))); } - OnCommandChanged.broadcast({CanonPath}); + for (const auto &S : ModifiedFiles.keys()) + OnCommandChanged.broadcast({S.str()}); + return ModifiedFiles; +} + +void OverlayCDB::setCompileCommand(PathRef File, + std::optional<tooling::CompileCommand> Cmd) { + llvm::StringMap<std::optional<tooling::CompileCommand>> NewCommands; + NewCommands[File] = std::move(Cmd); + setCompileCommands(NewCommands); } DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base) Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1335,21 +1335,18 @@ void ClangdLSPServer::applyConfiguration( const ConfigurationSettings &Settings) { - // Per-file update to the compilation database. - llvm::StringSet<> ModifiedFiles; + llvm::StringMap<std::optional<tooling::CompileCommand>> Commands; for (auto &Entry : Settings.compilationDatabaseChanges) { PathRef File = Entry.first; - auto Old = CDB->getCompileCommand(File); - auto New = - tooling::CompileCommand(std::move(Entry.second.workingDirectory), File, - std::move(Entry.second.compilationCommand), - /*Output=*/""); - if (Old != New) { - CDB->setCompileCommand(File, std::move(New)); - ModifiedFiles.insert(File); - } + if (Entry.second.compilationCommand.empty()) + Commands.insert({File, std::nullopt}); + else + Commands.insert({File, tooling::CompileCommand( + std::move(Entry.second.workingDirectory), File, + std::move(Entry.second.compilationCommand), + /*Output=*/"")}); } - + llvm::StringSet<> ModifiedFiles{CDB->setCompileCommands(std::move(Commands))}; Server->reparseOpenFilesIfNeeded( [&](llvm::StringRef File) { return ModifiedFiles.count(File) != 0; }); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits