-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[clangd] Add --strong-workspace-mode flag #172160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clangd @llvm/pr-subscribers-clang-tools-extra Author: Dominicentek (Dominicentek) ChangesAdds a new flag to clangd which enables strong workspace mode. So far, the only effect this has is changing the working directory for fallback commands to the current working directory of the clangd process. This is a fixed version of the #155905 patch without a UBSan error. Full diff: https://github.com/llvm/llvm-project/pull/172160.diff 7 Files Affected:
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index f8e6da73bbb1f..1518f177b06a0 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -554,6 +554,8 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
if (const auto &Dir = Params.initializationOptions.compilationDatabasePath)
CDBOpts.CompileCommandsDir = Dir;
CDBOpts.ContextProvider = Opts.ContextProvider;
+ if (Opts.StrongWorkspaceMode)
+ CDBOpts.applyFallbackWorkingDirectory(Opts.WorkspaceRoot);
BaseCDB =
std::make_unique<DirectoryBasedGlobalCompilationDatabase>(CDBOpts);
}
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index 4a1eae188f7eb..3ffaf67553dce 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -152,6 +152,11 @@ class ClangdServer {
/// FIXME: If not set, should use the current working directory.
std::optional<std::string> WorkspaceRoot;
+ /// Sets an alternate mode of operation. Current effects are:
+ /// - Using the current working directory as the working directory for
+ /// fallback commands
+ bool StrongWorkspaceMode = false;
+
/// The resource directory is used to find internal headers, overriding
/// defaults and -resource-dir compiler flag).
/// If std::nullopt, ClangdServer calls
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index c6afd0bc07cbd..d229a71867558 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -64,7 +64,9 @@ GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
if (FileExtension.empty() || FileExtension == ".h")
Argv.push_back("-xobjective-c++-header");
Argv.push_back(std::string(File));
- tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File),
+ tooling::CompileCommand Cmd(FallbackWorkingDirectory
+ ? *FallbackWorkingDirectory
+ : llvm::sys::path::parent_path(File),
llvm::sys::path::filename(File), std::move(Argv),
/*Output=*/"");
Cmd.Heuristic = "clangd fallback";
@@ -349,7 +351,8 @@ bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
DirectoryBasedGlobalCompilationDatabase::
DirectoryBasedGlobalCompilationDatabase(const Options &Opts)
- : Opts(Opts), Broadcaster(std::make_unique<BroadcastThread>(*this)) {
+ : GlobalCompilationDatabase(Opts.FallbackWorkingDirectory), Opts(Opts),
+ Broadcaster(std::make_unique<BroadcastThread>(*this)) {
if (!this->Opts.ContextProvider)
this->Opts.ContextProvider = [](llvm::StringRef) {
return Context::current().clone();
@@ -460,6 +463,21 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB(
return Result;
}
+void DirectoryBasedGlobalCompilationDatabase::Options::
+ applyFallbackWorkingDirectory(
+ std::optional<std::string> FallbackWorkingDirectory) {
+ if (FallbackWorkingDirectory)
+ this->FallbackWorkingDirectory = *FallbackWorkingDirectory;
+ else {
+ // Clangd is running in strong workspace mode but the client didn't
+ // specify a workspace path in the `initialize` request.
+ // Fallback to current working directory.
+ SmallString<256> CWD;
+ llvm::sys::fs::current_path(CWD);
+ this->FallbackWorkingDirectory = std::string(CWD);
+ }
+}
+
// The broadcast thread announces files with new compile commands to the world.
// Primarily this is used to enqueue them for background indexing.
//
@@ -759,9 +777,10 @@ DirectoryBasedGlobalCompilationDatabase::getProjectModules(PathRef File) const {
OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
std::vector<std::string> FallbackFlags,
- CommandMangler Mangler)
- : DelegatingCDB(Base), Mangler(std::move(Mangler)),
- FallbackFlags(std::move(FallbackFlags)) {}
+ CommandMangler Mangler,
+ std::optional<std::string> FallbackWorkingDirectory)
+ : DelegatingCDB(Base, FallbackWorkingDirectory),
+ Mangler(std::move(Mangler)), FallbackFlags(std::move(FallbackFlags)) {}
std::optional<tooling::CompileCommand>
OverlayCDB::getCompileCommand(PathRef File) const {
@@ -844,16 +863,20 @@ OverlayCDB::getProjectModules(PathRef File) const {
return MDB;
}
-DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base)
- : Base(Base) {
+DelegatingCDB::DelegatingCDB(
+ const GlobalCompilationDatabase *Base,
+ std::optional<std::string> FallbackWorkingDirectory)
+ : GlobalCompilationDatabase(FallbackWorkingDirectory), Base(Base) {
if (Base)
BaseChanged = Base->watch([this](const std::vector<std::string> Changes) {
OnCommandChanged.broadcast(Changes);
});
}
-DelegatingCDB::DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base)
- : DelegatingCDB(Base.get()) {
+DelegatingCDB::DelegatingCDB(
+ std::unique_ptr<GlobalCompilationDatabase> Base,
+ std::optional<std::string> FallbackWorkingDirectory)
+ : DelegatingCDB(Base.get(), FallbackWorkingDirectory) {
BaseOwner = std::move(Base);
}
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index 1d636d73664be..415c7f50f8606 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -35,6 +35,9 @@ struct ProjectInfo {
/// Provides compilation arguments used for parsing C and C++ files.
class GlobalCompilationDatabase {
public:
+ GlobalCompilationDatabase(
+ std::optional<std::string> FallbackWorkingDirectory = std::nullopt)
+ : FallbackWorkingDirectory(FallbackWorkingDirectory) {}
virtual ~GlobalCompilationDatabase() = default;
/// If there are any known-good commands for building this file, returns one.
@@ -69,14 +72,19 @@ class GlobalCompilationDatabase {
}
protected:
+ std::optional<std::string> FallbackWorkingDirectory;
mutable CommandChanged OnCommandChanged;
};
// Helper class for implementing GlobalCompilationDatabases that wrap others.
class DelegatingCDB : public GlobalCompilationDatabase {
public:
- DelegatingCDB(const GlobalCompilationDatabase *Base);
- DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base);
+ DelegatingCDB(
+ const GlobalCompilationDatabase *Base,
+ std::optional<std::string> FallbackWorkingDirectory = std::nullopt);
+ DelegatingCDB(
+ std::unique_ptr<GlobalCompilationDatabase> Base,
+ std::optional<std::string> FallbackWorkingDirectory = std::nullopt);
std::optional<tooling::CompileCommand>
getCompileCommand(PathRef File) const override;
@@ -117,6 +125,12 @@ class DirectoryBasedGlobalCompilationDatabase
// Only look for a compilation database in this one fixed directory.
// FIXME: fold this into config/context mechanism.
std::optional<Path> CompileCommandsDir;
+ // Working directory for fallback commands
+ // If unset, parent directory of file should be used
+ std::optional<std::string> FallbackWorkingDirectory;
+
+ void applyFallbackWorkingDirectory(
+ std::optional<std::string> FallbackWorkingDirectory);
};
DirectoryBasedGlobalCompilationDatabase(const Options &Opts);
@@ -194,9 +208,11 @@ class OverlayCDB : public DelegatingCDB {
// Base may be null, in which case no entries are inherited.
// FallbackFlags are added to the fallback compile command.
// Adjuster is applied to all commands, fallback or not.
- OverlayCDB(const GlobalCompilationDatabase *Base,
- std::vector<std::string> FallbackFlags = {},
- CommandMangler Mangler = nullptr);
+ OverlayCDB(
+ const GlobalCompilationDatabase *Base,
+ std::vector<std::string> FallbackFlags = {},
+ CommandMangler Mangler = nullptr,
+ std::optional<std::string> FallbackWorkingDirectory = std::nullopt);
std::optional<tooling::CompileCommand>
getCompileCommand(PathRef File) const override;
diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index df8d075e80596..9c6de40ebde0f 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -169,6 +169,8 @@ class Checker {
bool buildCommand(const ThreadsafeFS &TFS) {
log("Loading compilation database...");
DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
+ if (Opts.StrongWorkspaceMode)
+ CDBOpts.applyFallbackWorkingDirectory(Opts.WorkspaceRoot);
CDBOpts.CompileCommandsDir =
Config::current().CompileFlags.CDBSearch.FixedCDBPath;
BaseCDB =
@@ -178,8 +180,10 @@ class Checker {
getSystemIncludeExtractor(llvm::ArrayRef(Opts.QueryDriverGlobs));
if (Opts.ResourceDir)
Mangler.ResourceDir = *Opts.ResourceDir;
+
CDB = std::make_unique<OverlayCDB>(
- BaseCDB.get(), std::vector<std::string>{}, std::move(Mangler));
+ BaseCDB.get(), std::vector<std::string>{}, std::move(Mangler),
+ CDBOpts.FallbackWorkingDirectory);
if (auto TrueCmd = CDB->getCompileCommand(File)) {
Cmd = std::move(*TrueCmd);
@@ -502,7 +506,7 @@ bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
config::DiagnosticCallback Diag) const override {
config::Fragment F;
// If we're timing clang-tidy checks, implicitly disabling the slow ones
- // is counterproductive!
+ // is counterproductive!
if (CheckTidyTime.getNumOccurrences())
F.Diagnostics.ClangTidy.FastCheckFilter.emplace("None");
return {std::move(F).compile(Diag)};
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 4a990f8f716ca..54af3662470db 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -500,6 +500,17 @@ opt<bool> EnableConfig{
init(true),
};
+opt<bool> StrongWorkspaceMode{
+ "strong-workspace-mode",
+ cat(Features),
+ desc("An alternate mode of operation for clangd, where the clangd instance "
+ "is used to edit a single workspace.\n"
+ "When enabled, fallback commands use the workspace directory as their "
+ "working directory instead of the parent folder."),
+ init(false),
+ Hidden,
+};
+
opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc),
desc("Use files open in the editor when parsing "
"headers instead of reading from the disk"),
@@ -907,6 +918,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
}
if (!ResourceDir.empty())
Opts.ResourceDir = ResourceDir;
+ Opts.StrongWorkspaceMode = StrongWorkspaceMode;
Opts.BuildDynamicSymbolIndex = true;
#if CLANGD_ENABLE_REMOTE
if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {
diff --git a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index c9e01e52dac1f..39ab1446e980b 100644
--- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -55,6 +55,20 @@ TEST(GlobalCompilationDatabaseTest, FallbackCommand) {
testPath("foo/bar")));
}
+TEST(GlobalCompilationDatabaseTest, FallbackWorkingDirectory) {
+ MockFS TFS;
+ DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
+ CDBOpts.applyFallbackWorkingDirectory(testPath("foo"));
+ EXPECT_EQ(CDBOpts.FallbackWorkingDirectory, testPath("foo"));
+
+ DirectoryBasedGlobalCompilationDatabase DB(CDBOpts);
+ auto Cmd = DB.getFallbackCommand(testPath("foo/src/bar.cc"));
+ EXPECT_EQ(Cmd.Directory, testPath("foo"));
+ EXPECT_THAT(Cmd.CommandLine,
+ ElementsAre("clang", testPath("foo/src/bar.cc")));
+ EXPECT_EQ(Cmd.Output, "");
+}
+
static tooling::CompileCommand cmd(llvm::StringRef File, llvm::StringRef Arg) {
return tooling::CompileCommand(
testRoot(), File, {"clang", std::string(Arg), std::string(File)}, "");
|
Adds a new flag to clangd which enables strong workspace mode. So far, the only effect this has is changing the working directory for fallback commands to the current working directory of the clangd process.
This is a fixed version of the #155905 patch without a UBSan error.