https://github.com/Dominicentek updated 
https://github.com/llvm/llvm-project/pull/155905

>From 9a30c2b92be357deac5a65e2fa0952d91634de70 Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Thu, 28 Aug 2025 20:46:35 +0200
Subject: [PATCH 1/7] Add --project-root to clangd

---
 clang-tools-extra/clangd/ClangdServer.cpp          |  1 +
 clang-tools-extra/clangd/ClangdServer.h            |  4 ++++
 .../clangd/GlobalCompilationDatabase.cpp           | 14 +++++++-------
 .../clangd/GlobalCompilationDatabase.h             |  6 +++---
 clang-tools-extra/clangd/TUScheduler.cpp           |  6 ++++--
 clang-tools-extra/clangd/TUScheduler.h             |  4 ++++
 clang-tools-extra/clangd/tool/Check.cpp            |  4 ++--
 clang-tools-extra/clangd/tool/ClangdMain.cpp       | 10 ++++++++++
 8 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdServer.cpp 
b/clang-tools-extra/clangd/ClangdServer.cpp
index ac1e9aa5f0ff1..51230b4506b1a 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -208,6 +208,7 @@ ClangdServer::Options::operator TUScheduler::Options() 
const {
   Opts.UpdateDebounce = UpdateDebounce;
   Opts.ContextProvider = ContextProvider;
   Opts.PreambleThrottler = PreambleThrottler;
+  Opts.FallbackProjectRoot = FallbackProjectRoot;
   return Opts;
 }
 
diff --git a/clang-tools-extra/clangd/ClangdServer.h 
b/clang-tools-extra/clangd/ClangdServer.h
index 4a1eae188f7eb..2c56d6f7e6d6c 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -152,6 +152,10 @@ class ClangdServer {
     /// FIXME: If not set, should use the current working directory.
     std::optional<std::string> WorkspaceRoot;
 
+    /// If set, fallback command uses this path as its current working 
directory
+    /// instead of the file's parent path.
+    std::optional<std::string> FallbackProjectRoot;
+
     /// 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..b73697d4ee7e5 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -55,7 +55,7 @@ void actOnAllParentDirectories(PathRef FileName,
 } // namespace
 
 tooling::CompileCommand
-GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
+GlobalCompilationDatabase::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
   std::vector<std::string> Argv = {"clang"};
   // Clang treats .h files as C by default and files without extension as 
linker
   // input, resulting in unhelpful diagnostics.
@@ -64,7 +64,7 @@ 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(ProjectRoot ? *ProjectRoot : 
llvm::sys::path::parent_path(File),
                               llvm::sys::path::filename(File), std::move(Argv),
                               /*Output=*/"");
   Cmd.Heuristic = "clangd fallback";
@@ -797,8 +797,8 @@ OverlayCDB::getCompileCommand(PathRef File) const {
   return Cmd;
 }
 
-tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const {
-  auto Cmd = DelegatingCDB::getFallbackCommand(File);
+tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
+  auto Cmd = DelegatingCDB::getFallbackCommand(File, ProjectRoot);
   std::lock_guard<std::mutex> Lock(Mutex);
   Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
                          FallbackFlags.end());
@@ -877,10 +877,10 @@ DelegatingCDB::getProjectModules(PathRef File) const {
   return Base->getProjectModules(File);
 }
 
-tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File) const {
+tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
   if (!Base)
-    return GlobalCompilationDatabase::getFallbackCommand(File);
-  return Base->getFallbackCommand(File);
+    return GlobalCompilationDatabase::getFallbackCommand(File, ProjectRoot);
+  return Base->getFallbackCommand(File, ProjectRoot);
 }
 
 bool DelegatingCDB::blockUntilIdle(Deadline D) const {
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index 1d636d73664be..5d1b5cb632154 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -55,7 +55,7 @@ class GlobalCompilationDatabase {
   /// Makes a guess at how to build a file.
   /// The default implementation just runs clang on the file.
   /// Clangd should treat the results as unreliable.
-  virtual tooling::CompileCommand getFallbackCommand(PathRef File) const;
+  virtual tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const;
 
   /// If the CDB does any asynchronous work, wait for it to complete.
   /// For use in tests.
@@ -86,7 +86,7 @@ class DelegatingCDB : public GlobalCompilationDatabase {
   std::unique_ptr<ProjectModules>
   getProjectModules(PathRef File) const override;
 
-  tooling::CompileCommand getFallbackCommand(PathRef File) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const override;
 
   bool blockUntilIdle(Deadline D) const override;
 
@@ -200,7 +200,7 @@ class OverlayCDB : public DelegatingCDB {
 
   std::optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
-  tooling::CompileCommand getFallbackCommand(PathRef File) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const override;
 
   /// Sets or clears the compilation command for a particular file.
   /// Returns true if the command was changed (including insertion and 
removal),
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp 
b/clang-tools-extra/clangd/TUScheduler.cpp
index 035e5e63d8fbb..3dc53767e0ea4 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -723,6 +723,7 @@ class ASTWorker {
   const GlobalCompilationDatabase &CDB;
   /// Callback invoked when preamble or main file AST is built.
   ParsingCallbacks &Callbacks;
+  std::optional<std::string> FallbackProjectRoot;
 
   Semaphore &Barrier;
   /// Whether the 'onMainAST' callback ran for the current FileInputs.
@@ -840,13 +841,14 @@ ASTWorker::ASTWorker(PathRef FileName, const 
GlobalCompilationDatabase &CDB,
     : IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync),
       UpdateDebounce(Opts.UpdateDebounce), FileName(FileName),
       ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks),
+      FallbackProjectRoot(Opts.FallbackProjectRoot),
       Barrier(Barrier), Done(false), Status(FileName, Callbacks),
       PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync,
                    Opts.PreambleThrottler, Status, HeaderIncluders, *this) {
   // Set a fallback command because compile command can be accessed before
   // `Inputs` is initialized. Other fields are only used after initialization
   // from client inputs.
-  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName);
+  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName, 
FallbackProjectRoot);
 }
 
 ASTWorker::~ASTWorker() {
@@ -888,7 +890,7 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics 
WantDiags,
     if (Cmd)
       Inputs.CompileCommand = std::move(*Cmd);
     else
-      Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
+      Inputs.CompileCommand = CDB.getFallbackCommand(FileName, 
FallbackProjectRoot);
 
     bool InputsAreTheSame =
         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
diff --git a/clang-tools-extra/clangd/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index d0da20310a8b2..581a639646527 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -236,6 +236,10 @@ class TUScheduler {
     /// Typically to inject per-file configuration.
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
+
+    /// If set, fallback command uses this path as its current working 
directory
+    /// instead of the file's parent path.
+    std::optional<std::string> FallbackProjectRoot;
   };
 
   TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
diff --git a/clang-tools-extra/clangd/tool/Check.cpp 
b/clang-tools-extra/clangd/tool/Check.cpp
index df8d075e80596..8d49b82d2ca53 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -187,7 +187,7 @@ class Checker {
           Cmd.Heuristic.empty() ? "from CDB" : Cmd.Heuristic, Cmd.Directory,
           printArgv(Cmd.CommandLine));
     } else {
-      Cmd = CDB->getFallbackCommand(File);
+      Cmd = CDB->getFallbackCommand(File, Opts.FallbackProjectRoot);
       log("Generic fallback command is: [{0}] {1}", Cmd.Directory,
           printArgv(Cmd.CommandLine));
     }
@@ -502,7 +502,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 f287439f10cab..75d71c5a78f45 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -499,6 +499,14 @@ opt<bool> EnableConfig{
     init(true),
 };
 
+opt<Path> ProjectRoot{
+    "project-root",
+    cat(Misc),
+    desc("Path to use as the current working directory for fallback 
commands."),
+    init(""),
+    ValueOptional,
+};
+
 opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc),
                           desc("Use files open in the editor when parsing "
                                "headers instead of reading from the disk"),
@@ -906,6 +914,8 @@ clangd accepts flags on the commandline, and in the 
CLANGD_FLAGS environment var
   }
   if (!ResourceDir.empty())
     Opts.ResourceDir = ResourceDir;
+  if (!ProjectRoot.empty())
+    Opts.FallbackProjectRoot = ProjectRoot;
   Opts.BuildDynamicSymbolIndex = true;
 #if CLANGD_ENABLE_REMOTE
   if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {

>From 82f80c04f0a6cb8d1c759178a707057be9d5ad7d Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Mon, 24 Nov 2025 21:59:31 +0100
Subject: [PATCH 2/7] [clangd] Replace --project-root with
 --strong-workspace-mode

---
 clang-tools-extra/clangd/ClangdServer.cpp     |  2 +-
 clang-tools-extra/clangd/ClangdServer.h       |  6 +++---
 .../clangd/GlobalCompilationDatabase.cpp      | 19 ++++++++++++-------
 .../clangd/GlobalCompilationDatabase.h        |  6 +++---
 clang-tools-extra/clangd/TUScheduler.cpp      |  8 ++++----
 clang-tools-extra/clangd/TUScheduler.h        |  5 ++---
 clang-tools-extra/clangd/tool/Check.cpp       |  2 +-
 clang-tools-extra/clangd/tool/ClangdMain.cpp  | 16 ++++++++--------
 8 files changed, 34 insertions(+), 30 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdServer.cpp 
b/clang-tools-extra/clangd/ClangdServer.cpp
index 51230b4506b1a..882515e97eeb7 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -208,7 +208,7 @@ ClangdServer::Options::operator TUScheduler::Options() 
const {
   Opts.UpdateDebounce = UpdateDebounce;
   Opts.ContextProvider = ContextProvider;
   Opts.PreambleThrottler = PreambleThrottler;
-  Opts.FallbackProjectRoot = FallbackProjectRoot;
+  Opts.StrongWorkspaceMode = StrongWorkspaceMode;
   return Opts;
 }
 
diff --git a/clang-tools-extra/clangd/ClangdServer.h 
b/clang-tools-extra/clangd/ClangdServer.h
index 2c56d6f7e6d6c..3f3eaf4115669 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -152,9 +152,9 @@ class ClangdServer {
     /// FIXME: If not set, should use the current working directory.
     std::optional<std::string> WorkspaceRoot;
 
-    /// If set, fallback command uses this path as its current working 
directory
-    /// instead of the file's parent path.
-    std::optional<std::string> FallbackProjectRoot;
+    /// Sets an alterante mode of operation. Current effects are:
+    /// - Using the current working directory as the working directory for 
fallback commands
+    bool StrongWorkspaceMode;
 
     /// The resource directory is used to find internal headers, overriding
     /// defaults and -resource-dir compiler flag).
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index b73697d4ee7e5..4f161b38d96a2 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -55,7 +55,7 @@ void actOnAllParentDirectories(PathRef FileName,
 } // namespace
 
 tooling::CompileCommand
-GlobalCompilationDatabase::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
+GlobalCompilationDatabase::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
   std::vector<std::string> Argv = {"clang"};
   // Clang treats .h files as C by default and files without extension as 
linker
   // input, resulting in unhelpful diagnostics.
@@ -64,7 +64,12 @@ GlobalCompilationDatabase::getFallbackCommand(PathRef File, 
std::optional<std::s
   if (FileExtension.empty() || FileExtension == ".h")
     Argv.push_back("-xobjective-c++-header");
   Argv.push_back(std::string(File));
-  tooling::CompileCommand Cmd(ProjectRoot ? *ProjectRoot : 
llvm::sys::path::parent_path(File),
+  SmallString<256> WorkingDir;
+  if (StrongWorkspaceMode)
+    llvm::sys::fs::current_path(WorkingDir);
+  else
+    WorkingDir = llvm::sys::path::parent_path(File);
+  tooling::CompileCommand Cmd(WorkingDir,
                               llvm::sys::path::filename(File), std::move(Argv),
                               /*Output=*/"");
   Cmd.Heuristic = "clangd fallback";
@@ -797,8 +802,8 @@ OverlayCDB::getCompileCommand(PathRef File) const {
   return Cmd;
 }
 
-tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
-  auto Cmd = DelegatingCDB::getFallbackCommand(File, ProjectRoot);
+tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
+  auto Cmd = DelegatingCDB::getFallbackCommand(File, StrongWorkspaceMode);
   std::lock_guard<std::mutex> Lock(Mutex);
   Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
                          FallbackFlags.end());
@@ -877,10 +882,10 @@ DelegatingCDB::getProjectModules(PathRef File) const {
   return Base->getProjectModules(File);
 }
 
-tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot) const {
+tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
   if (!Base)
-    return GlobalCompilationDatabase::getFallbackCommand(File, ProjectRoot);
-  return Base->getFallbackCommand(File, ProjectRoot);
+    return GlobalCompilationDatabase::getFallbackCommand(File, 
StrongWorkspaceMode);
+  return Base->getFallbackCommand(File, StrongWorkspaceMode);
 }
 
 bool DelegatingCDB::blockUntilIdle(Deadline D) const {
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index 5d1b5cb632154..a23e8cc162c4e 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -55,7 +55,7 @@ class GlobalCompilationDatabase {
   /// Makes a guess at how to build a file.
   /// The default implementation just runs clang on the file.
   /// Clangd should treat the results as unreliable.
-  virtual tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const;
+  virtual tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const;
 
   /// If the CDB does any asynchronous work, wait for it to complete.
   /// For use in tests.
@@ -86,7 +86,7 @@ class DelegatingCDB : public GlobalCompilationDatabase {
   std::unique_ptr<ProjectModules>
   getProjectModules(PathRef File) const override;
 
-  tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const override;
 
   bool blockUntilIdle(Deadline D) const override;
 
@@ -200,7 +200,7 @@ class OverlayCDB : public DelegatingCDB {
 
   std::optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
-  tooling::CompileCommand getFallbackCommand(PathRef File, 
std::optional<std::string> ProjectRoot = std::nullopt) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const override;
 
   /// Sets or clears the compilation command for a particular file.
   /// Returns true if the command was changed (including insertion and 
removal),
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp 
b/clang-tools-extra/clangd/TUScheduler.cpp
index 3dc53767e0ea4..09bb8d1927e90 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -723,7 +723,7 @@ class ASTWorker {
   const GlobalCompilationDatabase &CDB;
   /// Callback invoked when preamble or main file AST is built.
   ParsingCallbacks &Callbacks;
-  std::optional<std::string> FallbackProjectRoot;
+  bool StrongWorkspaceMode;
 
   Semaphore &Barrier;
   /// Whether the 'onMainAST' callback ran for the current FileInputs.
@@ -841,14 +841,14 @@ ASTWorker::ASTWorker(PathRef FileName, const 
GlobalCompilationDatabase &CDB,
     : IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync),
       UpdateDebounce(Opts.UpdateDebounce), FileName(FileName),
       ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks),
-      FallbackProjectRoot(Opts.FallbackProjectRoot),
+      StrongWorkspaceMode(Opts.StrongWorkspaceMode),
       Barrier(Barrier), Done(false), Status(FileName, Callbacks),
       PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync,
                    Opts.PreambleThrottler, Status, HeaderIncluders, *this) {
   // Set a fallback command because compile command can be accessed before
   // `Inputs` is initialized. Other fields are only used after initialization
   // from client inputs.
-  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName, 
FallbackProjectRoot);
+  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName, 
StrongWorkspaceMode);
 }
 
 ASTWorker::~ASTWorker() {
@@ -890,7 +890,7 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics 
WantDiags,
     if (Cmd)
       Inputs.CompileCommand = std::move(*Cmd);
     else
-      Inputs.CompileCommand = CDB.getFallbackCommand(FileName, 
FallbackProjectRoot);
+      Inputs.CompileCommand = CDB.getFallbackCommand(FileName, 
StrongWorkspaceMode);
 
     bool InputsAreTheSame =
         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
diff --git a/clang-tools-extra/clangd/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index 581a639646527..d5dbd0e1830d1 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -237,9 +237,8 @@ class TUScheduler {
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
 
-    /// If set, fallback command uses this path as its current working 
directory
-    /// instead of the file's parent path.
-    std::optional<std::string> FallbackProjectRoot;
+    /// Sets an alterante mode of operation. See 
ClangdServer::Options::StrongWorkspaceMode.
+    bool StrongWorkspaceMode;
   };
 
   TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
diff --git a/clang-tools-extra/clangd/tool/Check.cpp 
b/clang-tools-extra/clangd/tool/Check.cpp
index 8d49b82d2ca53..451cdbce56fea 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -187,7 +187,7 @@ class Checker {
           Cmd.Heuristic.empty() ? "from CDB" : Cmd.Heuristic, Cmd.Directory,
           printArgv(Cmd.CommandLine));
     } else {
-      Cmd = CDB->getFallbackCommand(File, Opts.FallbackProjectRoot);
+      Cmd = CDB->getFallbackCommand(File, Opts.StrongWorkspaceMode);
       log("Generic fallback command is: [{0}] {1}", Cmd.Directory,
           printArgv(Cmd.CommandLine));
     }
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp 
b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 7d2db715d37fd..f947171090a46 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -500,12 +500,13 @@ opt<bool> EnableConfig{
     init(true),
 };
 
-opt<Path> ProjectRoot{
-    "project-root",
-    cat(Misc),
-    desc("Path to use as the current working directory for fallback 
commands."),
-    init(""),
-    ValueOptional,
+opt<bool> StrongWorkspaceMode{
+    "strong-workspace-mode",
+    cat(Features),
+    desc(
+        "An alternate mode of operation for clangd, operating more closely to 
the workspace.\n"
+        "When enabled, fallback commands use the workspace directory as their 
working directory instead of the parent folder."),
+    init(false),
 };
 
 opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc),
@@ -915,8 +916,7 @@ clangd accepts flags on the commandline, and in the 
CLANGD_FLAGS environment var
   }
   if (!ResourceDir.empty())
     Opts.ResourceDir = ResourceDir;
-  if (!ProjectRoot.empty())
-    Opts.FallbackProjectRoot = ProjectRoot;
+  Opts.StrongWorkspaceMode = StrongWorkspaceMode;
   Opts.BuildDynamicSymbolIndex = true;
 #if CLANGD_ENABLE_REMOTE
   if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {

>From 03b26a6f54e9e0dc3fe6e26e1e8060f3c6a6d112 Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Tue, 25 Nov 2025 20:25:08 +0100
Subject: [PATCH 3/7] [clangd] Fallback working directory code cleanup

---
 clang-tools-extra/clangd/ClangdLSPServer.cpp  |  2 +
 clang-tools-extra/clangd/ClangdServer.cpp     |  1 -
 .../clangd/GlobalCompilationDatabase.cpp      | 53 +++++++++++--------
 .../clangd/GlobalCompilationDatabase.h        | 24 ++++++---
 clang-tools-extra/clangd/TUScheduler.cpp      |  5 +-
 clang-tools-extra/clangd/TUScheduler.h        |  3 --
 clang-tools-extra/clangd/tool/Check.cpp       |  8 ++-
 .../GlobalCompilationDatabaseTests.cpp        | 14 +++++
 8 files changed, 74 insertions(+), 36 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp 
b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index f8e6da73bbb1f..3e8bacc715494 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.applyWorkingDirectory(std::move(Opts.WorkspaceRoot));
     BaseCDB =
         std::make_unique<DirectoryBasedGlobalCompilationDatabase>(CDBOpts);
   }
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp 
b/clang-tools-extra/clangd/ClangdServer.cpp
index 882515e97eeb7..ac1e9aa5f0ff1 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -208,7 +208,6 @@ ClangdServer::Options::operator TUScheduler::Options() 
const {
   Opts.UpdateDebounce = UpdateDebounce;
   Opts.ContextProvider = ContextProvider;
   Opts.PreambleThrottler = PreambleThrottler;
-  Opts.StrongWorkspaceMode = StrongWorkspaceMode;
   return Opts;
 }
 
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 4f161b38d96a2..e2ac2d17171be 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -55,7 +55,7 @@ void actOnAllParentDirectories(PathRef FileName,
 } // namespace
 
 tooling::CompileCommand
-GlobalCompilationDatabase::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
+GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
   std::vector<std::string> Argv = {"clang"};
   // Clang treats .h files as C by default and files without extension as 
linker
   // input, resulting in unhelpful diagnostics.
@@ -64,14 +64,10 @@ GlobalCompilationDatabase::getFallbackCommand(PathRef File, 
bool StrongWorkspace
   if (FileExtension.empty() || FileExtension == ".h")
     Argv.push_back("-xobjective-c++-header");
   Argv.push_back(std::string(File));
-  SmallString<256> WorkingDir;
-  if (StrongWorkspaceMode)
-    llvm::sys::fs::current_path(WorkingDir);
-  else
-    WorkingDir = llvm::sys::path::parent_path(File);
-  tooling::CompileCommand Cmd(WorkingDir,
-                              llvm::sys::path::filename(File), std::move(Argv),
-                              /*Output=*/"");
+  tooling::CompileCommand Cmd(
+      WorkingDirectory ? *WorkingDirectory : 
llvm::sys::path::parent_path(File),
+      llvm::sys::path::filename(File), std::move(Argv),
+      /*Output=*/"");
   Cmd.Heuristic = "clangd fallback";
   return Cmd;
 }
@@ -354,7 +350,8 @@ bool 
DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
 
 DirectoryBasedGlobalCompilationDatabase::
     DirectoryBasedGlobalCompilationDatabase(const Options &Opts)
-    : Opts(Opts), Broadcaster(std::make_unique<BroadcastThread>(*this)) {
+    : GlobalCompilationDatabase(Opts.WorkingDirectory), Opts(Opts),
+      Broadcaster(std::make_unique<BroadcastThread>(*this)) {
   if (!this->Opts.ContextProvider)
     this->Opts.ContextProvider = [](llvm::StringRef) {
       return Context::current().clone();
@@ -465,6 +462,17 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB(
   return Result;
 }
 
+void DirectoryBasedGlobalCompilationDatabase::Options::applyWorkingDirectory(
+    const std::optional<std::string> &&WorkingDirectory) {
+  if (WorkingDirectory)
+    this->WorkingDirectory = *WorkingDirectory;
+  else {
+    SmallString<256> CWD;
+    llvm::sys::fs::current_path(CWD);
+    this->WorkingDirectory = 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.
 //
@@ -764,8 +772,9 @@ 
DirectoryBasedGlobalCompilationDatabase::getProjectModules(PathRef File) const {
 
 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
                        std::vector<std::string> FallbackFlags,
-                       CommandMangler Mangler)
-    : DelegatingCDB(Base), Mangler(std::move(Mangler)),
+                       CommandMangler Mangler,
+                       std::optional<std::string> WorkingDirectory)
+    : DelegatingCDB(Base, WorkingDirectory), Mangler(std::move(Mangler)),
       FallbackFlags(std::move(FallbackFlags)) {}
 
 std::optional<tooling::CompileCommand>
@@ -802,8 +811,8 @@ OverlayCDB::getCompileCommand(PathRef File) const {
   return Cmd;
 }
 
-tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
-  auto Cmd = DelegatingCDB::getFallbackCommand(File, StrongWorkspaceMode);
+tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const {
+  auto Cmd = DelegatingCDB::getFallbackCommand(File);
   std::lock_guard<std::mutex> Lock(Mutex);
   Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
                          FallbackFlags.end());
@@ -849,16 +858,18 @@ OverlayCDB::getProjectModules(PathRef File) const {
   return MDB;
 }
 
-DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base)
-    : Base(Base) {
+DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base,
+                             std::optional<std::string> WorkingDirectory)
+    : GlobalCompilationDatabase(WorkingDirectory), 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> WorkingDirectory)
+    : DelegatingCDB(Base.get(), WorkingDirectory) {
   BaseOwner = std::move(Base);
 }
 
@@ -882,10 +893,10 @@ DelegatingCDB::getProjectModules(PathRef File) const {
   return Base->getProjectModules(File);
 }
 
-tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode) const {
+tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File) const {
   if (!Base)
-    return GlobalCompilationDatabase::getFallbackCommand(File, 
StrongWorkspaceMode);
-  return Base->getFallbackCommand(File, StrongWorkspaceMode);
+    return GlobalCompilationDatabase::getFallbackCommand(File);
+  return Base->getFallbackCommand(File);
 }
 
 bool DelegatingCDB::blockUntilIdle(Deadline D) const {
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index a23e8cc162c4e..da005f8e19c4c 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -35,6 +35,8 @@ struct ProjectInfo {
 /// Provides compilation arguments used for parsing C and C++ files.
 class GlobalCompilationDatabase {
 public:
+  GlobalCompilationDatabase(std::optional<std::string> WorkingDirectory)
+      : WorkingDirectory(WorkingDirectory) {}
   virtual ~GlobalCompilationDatabase() = default;
 
   /// If there are any known-good commands for building this file, returns one.
@@ -55,7 +57,7 @@ class GlobalCompilationDatabase {
   /// Makes a guess at how to build a file.
   /// The default implementation just runs clang on the file.
   /// Clangd should treat the results as unreliable.
-  virtual tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const;
+  virtual tooling::CompileCommand getFallbackCommand(PathRef File) const;
 
   /// If the CDB does any asynchronous work, wait for it to complete.
   /// For use in tests.
@@ -69,14 +71,17 @@ class GlobalCompilationDatabase {
   }
 
 protected:
+  std::optional<std::string> WorkingDirectory;
   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> WorkingDirectory);
+  DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base,
+                std::optional<std::string> WorkingDirectory);
 
   std::optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
@@ -86,7 +91,7 @@ class DelegatingCDB : public GlobalCompilationDatabase {
   std::unique_ptr<ProjectModules>
   getProjectModules(PathRef File) const override;
 
-  tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File) const override;
 
   bool blockUntilIdle(Deadline D) const override;
 
@@ -117,6 +122,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> WorkingDirectory;
+
+    void
+    applyWorkingDirectory(const std::optional<std::string> &&WorkingDirectory);
   };
 
   DirectoryBasedGlobalCompilationDatabase(const Options &Opts);
@@ -196,11 +207,12 @@ class OverlayCDB : public DelegatingCDB {
   // Adjuster is applied to all commands, fallback or not.
   OverlayCDB(const GlobalCompilationDatabase *Base,
              std::vector<std::string> FallbackFlags = {},
-             CommandMangler Mangler = nullptr);
+             CommandMangler Mangler = nullptr,
+             std::optional<std::string> WorkingDirectory = std::nullopt);
 
   std::optional<tooling::CompileCommand>
   getCompileCommand(PathRef File) const override;
-  tooling::CompileCommand getFallbackCommand(PathRef File, bool 
StrongWorkspaceMode = false) const override;
+  tooling::CompileCommand getFallbackCommand(PathRef File) const override;
 
   /// Sets or clears the compilation command for a particular file.
   /// Returns true if the command was changed (including insertion and 
removal),
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp 
b/clang-tools-extra/clangd/TUScheduler.cpp
index 09bb8d1927e90..0a8bca76879b7 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -841,14 +841,13 @@ ASTWorker::ASTWorker(PathRef FileName, const 
GlobalCompilationDatabase &CDB,
     : IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync),
       UpdateDebounce(Opts.UpdateDebounce), FileName(FileName),
       ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks),
-      StrongWorkspaceMode(Opts.StrongWorkspaceMode),
       Barrier(Barrier), Done(false), Status(FileName, Callbacks),
       PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync,
                    Opts.PreambleThrottler, Status, HeaderIncluders, *this) {
   // Set a fallback command because compile command can be accessed before
   // `Inputs` is initialized. Other fields are only used after initialization
   // from client inputs.
-  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName, 
StrongWorkspaceMode);
+  FileInputs.CompileCommand = CDB.getFallbackCommand(FileName);
 }
 
 ASTWorker::~ASTWorker() {
@@ -890,7 +889,7 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics 
WantDiags,
     if (Cmd)
       Inputs.CompileCommand = std::move(*Cmd);
     else
-      Inputs.CompileCommand = CDB.getFallbackCommand(FileName, 
StrongWorkspaceMode);
+      Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
 
     bool InputsAreTheSame =
         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
diff --git a/clang-tools-extra/clangd/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index d5dbd0e1830d1..d0da20310a8b2 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -236,9 +236,6 @@ class TUScheduler {
     /// Typically to inject per-file configuration.
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
-
-    /// Sets an alterante mode of operation. See 
ClangdServer::Options::StrongWorkspaceMode.
-    bool StrongWorkspaceMode;
   };
 
   TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
diff --git a/clang-tools-extra/clangd/tool/Check.cpp 
b/clang-tools-extra/clangd/tool/Check.cpp
index 451cdbce56fea..6fc2b00cbc063 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.applyWorkingDirectory(std::move(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.WorkingDirectory);
 
     if (auto TrueCmd = CDB->getCompileCommand(File)) {
       Cmd = std::move(*TrueCmd);
@@ -187,7 +191,7 @@ class Checker {
           Cmd.Heuristic.empty() ? "from CDB" : Cmd.Heuristic, Cmd.Directory,
           printArgv(Cmd.CommandLine));
     } else {
-      Cmd = CDB->getFallbackCommand(File, Opts.StrongWorkspaceMode);
+      Cmd = CDB->getFallbackCommand(File);
       log("Generic fallback command is: [{0}] {1}", Cmd.Directory,
           printArgv(Cmd.CommandLine));
     }
diff --git 
a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp 
b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index c9e01e52dac1f..f4ff7d83d7047 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.applyWorkingDirectory(testPath("foo"));
+  EXPECT_EQ(CDBOpts.WorkingDirectory, 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)}, "");

>From f824d5d303d89b87a82873c9731b19297984e560 Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Wed, 26 Nov 2025 00:30:57 +0100
Subject: [PATCH 4/7] Fix formatting and errors

---
 clang-tools-extra/clangd/ClangdServer.h      | 3 ++-
 clang-tools-extra/clangd/TUScheduler.cpp     | 1 -
 clang-tools-extra/clangd/tool/ClangdMain.cpp | 7 ++++---
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdServer.h 
b/clang-tools-extra/clangd/ClangdServer.h
index 3f3eaf4115669..6ed5db517eb5e 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -153,7 +153,8 @@ class ClangdServer {
     std::optional<std::string> WorkspaceRoot;
 
     /// Sets an alterante mode of operation. Current effects are:
-    /// - Using the current working directory as the working directory for 
fallback commands
+    /// - Using the current working directory as the working directory for
+    /// fallback commands
     bool StrongWorkspaceMode;
 
     /// The resource directory is used to find internal headers, overriding
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp 
b/clang-tools-extra/clangd/TUScheduler.cpp
index 0a8bca76879b7..035e5e63d8fbb 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -723,7 +723,6 @@ class ASTWorker {
   const GlobalCompilationDatabase &CDB;
   /// Callback invoked when preamble or main file AST is built.
   ParsingCallbacks &Callbacks;
-  bool StrongWorkspaceMode;
 
   Semaphore &Barrier;
   /// Whether the 'onMainAST' callback ran for the current FileInputs.
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp 
b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index f947171090a46..39f2a8c8346c6 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -503,9 +503,10 @@ opt<bool> EnableConfig{
 opt<bool> StrongWorkspaceMode{
     "strong-workspace-mode",
     cat(Features),
-    desc(
-        "An alternate mode of operation for clangd, operating more closely to 
the workspace.\n"
-        "When enabled, fallback commands use the workspace directory as their 
working directory instead of the parent folder."),
+    desc("An alternate mode of operation for clangd, operating more closely to 
"
+         "the workspace.\n"
+         "When enabled, fallback commands use the workspace directory as their 
"
+         "working directory instead of the parent folder."),
     init(false),
 };
 

>From 220b823d46554ddbb694b3518133705efb1b1e71 Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Wed, 26 Nov 2025 17:17:24 +0100
Subject: [PATCH 5/7] [clangd] Make tests compile with new CDB constructor

---
 clang-tools-extra/clangd/TUScheduler.h                          | 2 ++
 clang-tools-extra/clangd/unittests/ClangdTests.cpp              | 2 +-
 .../clangd/unittests/GlobalCompilationDatabaseTests.cpp         | 2 ++
 clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp         | 2 ++
 clang-tools-extra/clangd/unittests/TestFS.cpp                   | 2 +-
 5 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clangd/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index d0da20310a8b2..7b7872a4e8595 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -236,6 +236,8 @@ class TUScheduler {
     /// Typically to inject per-file configuration.
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
+    
+    bool test;
   };
 
   TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp 
b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index 9ea7c3e02411d..b935d91c6bd81 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -1110,7 +1110,7 @@ TEST(ClangdServerTest, 
FallbackWhenWaitingForCompileCommand) {
   class DelayedCompilationDatabase : public GlobalCompilationDatabase {
   public:
     DelayedCompilationDatabase(Notification &CanReturnCommand)
-        : CanReturnCommand(CanReturnCommand) {}
+        : GlobalCompilationDatabase(std::nullopt), 
CanReturnCommand(CanReturnCommand) {}
 
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
diff --git 
a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp 
b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index f4ff7d83d7047..57a1f40cfa571 100644
--- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -77,6 +77,8 @@ static tooling::CompileCommand cmd(llvm::StringRef File, 
llvm::StringRef Arg) {
 class OverlayCDBTest : public ::testing::Test {
   class BaseCDB : public GlobalCompilationDatabase {
   public:
+    BaseCDB(): GlobalCompilationDatabase(std::nullopt) {}
+  
     std::optional<tooling::CompileCommand>
     getCompileCommand(llvm::StringRef File) const override {
       if (File == testPath("foo.cc"))
diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp 
b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
index 43f38e39c8952..59421375d1cdd 100644
--- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -1329,6 +1329,8 @@ TEST_F(TUSchedulerTests, IncluderCache) {
                      OK = testPath("ok.h"),
                      NotIncluded = testPath("not_included.h");
   struct NoHeadersCDB : public GlobalCompilationDatabase {
+      NoHeadersCDB(): GlobalCompilationDatabase(std::nullopt) {}
+      
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
       if (File == NoCmd || File == NotIncluded || FailAll)
diff --git a/clang-tools-extra/clangd/unittests/TestFS.cpp 
b/clang-tools-extra/clangd/unittests/TestFS.cpp
index bb309609eda20..37783cc0f443d 100644
--- a/clang-tools-extra/clangd/unittests/TestFS.cpp
+++ b/clang-tools-extra/clangd/unittests/TestFS.cpp
@@ -46,7 +46,7 @@ buildTestFS(llvm::StringMap<std::string> const &Files,
 
 MockCompilationDatabase::MockCompilationDatabase(llvm::StringRef Directory,
                                                  llvm::StringRef RelPathPrefix)
-    : ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
+    : GlobalCompilationDatabase(std::nullopt), 
ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
       RelPathPrefix(RelPathPrefix) {
   // -ffreestanding avoids implicit stdc-predef.h.
 }

>From a21f748b3379b4d7c3588c008423ef6e565e906d Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Wed, 26 Nov 2025 17:33:12 +0100
Subject: [PATCH 6/7] Run git-clang-format

---
 clang-tools-extra/clangd/TUScheduler.h                        | 2 +-
 clang-tools-extra/clangd/unittests/ClangdTests.cpp            | 3 ++-
 .../clangd/unittests/GlobalCompilationDatabaseTests.cpp       | 4 ++--
 clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp       | 4 ++--
 clang-tools-extra/clangd/unittests/TestFS.cpp                 | 3 ++-
 5 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clangd/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index 7b7872a4e8595..e23a4d63bf297 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -236,7 +236,7 @@ class TUScheduler {
     /// Typically to inject per-file configuration.
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
-    
+
     bool test;
   };
 
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp 
b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index b935d91c6bd81..24ca8c93fb2d3 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -1110,7 +1110,8 @@ TEST(ClangdServerTest, 
FallbackWhenWaitingForCompileCommand) {
   class DelayedCompilationDatabase : public GlobalCompilationDatabase {
   public:
     DelayedCompilationDatabase(Notification &CanReturnCommand)
-        : GlobalCompilationDatabase(std::nullopt), 
CanReturnCommand(CanReturnCommand) {}
+        : GlobalCompilationDatabase(std::nullopt),
+          CanReturnCommand(CanReturnCommand) {}
 
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
diff --git 
a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp 
b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index 57a1f40cfa571..631cbc1be12e8 100644
--- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -77,8 +77,8 @@ static tooling::CompileCommand cmd(llvm::StringRef File, 
llvm::StringRef Arg) {
 class OverlayCDBTest : public ::testing::Test {
   class BaseCDB : public GlobalCompilationDatabase {
   public:
-    BaseCDB(): GlobalCompilationDatabase(std::nullopt) {}
-  
+    BaseCDB() : GlobalCompilationDatabase(std::nullopt) {}
+
     std::optional<tooling::CompileCommand>
     getCompileCommand(llvm::StringRef File) const override {
       if (File == testPath("foo.cc"))
diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp 
b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
index 59421375d1cdd..531067095464c 100644
--- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -1329,8 +1329,8 @@ TEST_F(TUSchedulerTests, IncluderCache) {
                      OK = testPath("ok.h"),
                      NotIncluded = testPath("not_included.h");
   struct NoHeadersCDB : public GlobalCompilationDatabase {
-      NoHeadersCDB(): GlobalCompilationDatabase(std::nullopt) {}
-      
+    NoHeadersCDB() : GlobalCompilationDatabase(std::nullopt) {}
+
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
       if (File == NoCmd || File == NotIncluded || FailAll)
diff --git a/clang-tools-extra/clangd/unittests/TestFS.cpp 
b/clang-tools-extra/clangd/unittests/TestFS.cpp
index 37783cc0f443d..33efc3651d359 100644
--- a/clang-tools-extra/clangd/unittests/TestFS.cpp
+++ b/clang-tools-extra/clangd/unittests/TestFS.cpp
@@ -46,7 +46,8 @@ buildTestFS(llvm::StringMap<std::string> const &Files,
 
 MockCompilationDatabase::MockCompilationDatabase(llvm::StringRef Directory,
                                                  llvm::StringRef RelPathPrefix)
-    : GlobalCompilationDatabase(std::nullopt), 
ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
+    : GlobalCompilationDatabase(std::nullopt),
+      ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
       RelPathPrefix(RelPathPrefix) {
   // -ffreestanding avoids implicit stdc-predef.h.
 }

>From f677937b299783771273ed2cfd49ba3bb18b0414 Mon Sep 17 00:00:00 2001
From: Dominicentek <[email protected]>
Date: Sat, 29 Nov 2025 13:07:06 +0100
Subject: [PATCH 7/7] Implement suggestions

---
 .../clangd/GlobalCompilationDatabase.cpp      | 13 +++++----
 .../clangd/GlobalCompilationDatabase.h        | 29 ++++++++++---------
 clang-tools-extra/clangd/TUScheduler.h        |  2 --
 clang-tools-extra/clangd/tool/ClangdMain.cpp  |  5 ++--
 .../clangd/unittests/ClangdTests.cpp          |  3 +-
 .../GlobalCompilationDatabaseTests.cpp        |  2 --
 .../clangd/unittests/TUSchedulerTests.cpp     |  1 -
 clang-tools-extra/clangd/unittests/TestFS.cpp |  3 +-
 8 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index e2ac2d17171be..12fa054f73051 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -64,10 +64,11 @@ 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(
-      WorkingDirectory ? *WorkingDirectory : 
llvm::sys::path::parent_path(File),
-      llvm::sys::path::filename(File), std::move(Argv),
-      /*Output=*/"");
+  tooling::CompileCommand Cmd(FallbackWorkingDirectory
+                                  ? *FallbackWorkingDirectory
+                                  : llvm::sys::path::parent_path(File),
+                              llvm::sys::path::filename(File), std::move(Argv),
+                              /*Output=*/"");
   Cmd.Heuristic = "clangd fallback";
   return Cmd;
 }
@@ -463,10 +464,12 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB(
 }
 
 void DirectoryBasedGlobalCompilationDatabase::Options::applyWorkingDirectory(
-    const std::optional<std::string> &&WorkingDirectory) {
+    std::optional<std::string> WorkingDirectory) {
   if (WorkingDirectory)
     this->WorkingDirectory = *WorkingDirectory;
   else {
+    // Fallback to current working directory if workspace path (passed as
+    // WorkingDirectory) is unset
     SmallString<256> CWD;
     llvm::sys::fs::current_path(CWD);
     this->WorkingDirectory = std::string(CWD);
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h 
b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index da005f8e19c4c..74ed46418d18d 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -35,8 +35,9 @@ struct ProjectInfo {
 /// Provides compilation arguments used for parsing C and C++ files.
 class GlobalCompilationDatabase {
 public:
-  GlobalCompilationDatabase(std::optional<std::string> WorkingDirectory)
-      : WorkingDirectory(WorkingDirectory) {}
+  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.
@@ -71,17 +72,19 @@ class GlobalCompilationDatabase {
   }
 
 protected:
-  std::optional<std::string> WorkingDirectory;
+  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,
-                std::optional<std::string> WorkingDirectory);
-  DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base,
-                std::optional<std::string> WorkingDirectory);
+  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;
@@ -126,8 +129,7 @@ class DirectoryBasedGlobalCompilationDatabase
     // If unset, parent directory of file should be used
     std::optional<std::string> WorkingDirectory;
 
-    void
-    applyWorkingDirectory(const std::optional<std::string> &&WorkingDirectory);
+    void applyWorkingDirectory(std::optional<std::string> WorkingDirectory);
   };
 
   DirectoryBasedGlobalCompilationDatabase(const Options &Opts);
@@ -205,10 +207,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,
-             std::optional<std::string> WorkingDirectory = std::nullopt);
+  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/TUScheduler.h 
b/clang-tools-extra/clangd/TUScheduler.h
index e23a4d63bf297..d0da20310a8b2 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -236,8 +236,6 @@ class TUScheduler {
     /// Typically to inject per-file configuration.
     /// If the path is empty, context sholud be "generic".
     std::function<Context(PathRef)> ContextProvider;
-
-    bool test;
   };
 
   TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp 
b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 39f2a8c8346c6..54af3662470db 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -503,11 +503,12 @@ opt<bool> EnableConfig{
 opt<bool> StrongWorkspaceMode{
     "strong-workspace-mode",
     cat(Features),
-    desc("An alternate mode of operation for clangd, operating more closely to 
"
-         "the workspace.\n"
+    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),
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp 
b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index 24ca8c93fb2d3..9ea7c3e02411d 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -1110,8 +1110,7 @@ TEST(ClangdServerTest, 
FallbackWhenWaitingForCompileCommand) {
   class DelayedCompilationDatabase : public GlobalCompilationDatabase {
   public:
     DelayedCompilationDatabase(Notification &CanReturnCommand)
-        : GlobalCompilationDatabase(std::nullopt),
-          CanReturnCommand(CanReturnCommand) {}
+        : CanReturnCommand(CanReturnCommand) {}
 
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
diff --git 
a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp 
b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
index 631cbc1be12e8..f4ff7d83d7047 100644
--- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
+++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp
@@ -77,8 +77,6 @@ static tooling::CompileCommand cmd(llvm::StringRef File, 
llvm::StringRef Arg) {
 class OverlayCDBTest : public ::testing::Test {
   class BaseCDB : public GlobalCompilationDatabase {
   public:
-    BaseCDB() : GlobalCompilationDatabase(std::nullopt) {}
-
     std::optional<tooling::CompileCommand>
     getCompileCommand(llvm::StringRef File) const override {
       if (File == testPath("foo.cc"))
diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp 
b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
index 531067095464c..cbfb5ee90fc06 100644
--- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -1329,7 +1329,6 @@ TEST_F(TUSchedulerTests, IncluderCache) {
                      OK = testPath("ok.h"),
                      NotIncluded = testPath("not_included.h");
   struct NoHeadersCDB : public GlobalCompilationDatabase {
-    NoHeadersCDB() : GlobalCompilationDatabase(std::nullopt) {}
 
     std::optional<tooling::CompileCommand>
     getCompileCommand(PathRef File) const override {
diff --git a/clang-tools-extra/clangd/unittests/TestFS.cpp 
b/clang-tools-extra/clangd/unittests/TestFS.cpp
index 33efc3651d359..bb309609eda20 100644
--- a/clang-tools-extra/clangd/unittests/TestFS.cpp
+++ b/clang-tools-extra/clangd/unittests/TestFS.cpp
@@ -46,8 +46,7 @@ buildTestFS(llvm::StringMap<std::string> const &Files,
 
 MockCompilationDatabase::MockCompilationDatabase(llvm::StringRef Directory,
                                                  llvm::StringRef RelPathPrefix)
-    : GlobalCompilationDatabase(std::nullopt),
-      ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
+    : ExtraClangFlags({"-ffreestanding"}), Directory(Directory),
       RelPathPrefix(RelPathPrefix) {
   // -ffreestanding avoids implicit stdc-predef.h.
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to