[clang] [clang-tools-extra] [clangd] [C++20] [Modules] Build Database Support (PR #199384)

Matthew Asplund via cfe-commits cfe-commits at lists.llvm.org
Sun May 24 21:02:56 PDT 2026


https://github.com/mwasplund updated https://github.com/llvm/llvm-project/pull/199384

>From 477b3130e1b64160268e480d61568ade76993127 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Wed, 13 May 2026 12:33:48 -0700
Subject: [PATCH 01/12] Move Compilation Database out of module file cache. It
 is not used in this class at all.

---
 clang-tools-extra/clangd/ModulesBuilder.cpp | 11 +++++------
 clang-tools-extra/clangd/ModulesBuilder.h   |  2 +-
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 706fd459e15ec..62d5e21f7c857 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -730,8 +730,7 @@ bool ReusablePrerequisiteModules::canReuse(
 /// variants do not collide.
 class ModuleFileCache {
 public:
-  ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
-  const GlobalCompilationDatabase &getCDB() const { return CDB; }
+  ModuleFileCache() {}
 
   std::shared_ptr<const ModuleFile> getModule(StringRef ModuleName,
                                               PathRef ModuleUnitSource,
@@ -762,8 +761,6 @@ class ModuleFileCache {
     return Key;
   }
 
-  const GlobalCompilationDatabase &CDB;
-
   llvm::StringMap<std::weak_ptr<const ModuleFile>> ModuleFiles;
   std::mutex ModuleFilesMutex;
 };
@@ -1008,12 +1005,13 @@ void garbageCollectModuleCache(PathRef CacheRoot) {
 
 class ModulesBuilder::ModulesBuilderImpl {
 public:
-  ModulesBuilderImpl(const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
+  ModulesBuilderImpl(const GlobalCompilationDatabase &CDB)
+      : CDB(CDB), Cache() {}
 
   ModuleNameToSourceCache &getProjectModulesCache() {
     return ProjectModulesCache;
   }
-  const GlobalCompilationDatabase &getCDB() const { return Cache.getCDB(); }
+  const GlobalCompilationDatabase &getCDB() const { return CDB; }
 
   llvm::Error
   getOrBuildModuleFile(PathRef RequiredSource, StringRef ModuleName,
@@ -1029,6 +1027,7 @@ class ModulesBuilder::ModulesBuilderImpl {
   /// Runs GC once for the cache root owning a project root.
   void garbageCollectModuleCacheForProjectRoot(PathRef ProjectRoot);
 
+  const GlobalCompilationDatabase &CDB;
   ModuleFileCache Cache;
   ModuleNameToSourceCache ProjectModulesCache;
   std::mutex GarbageCollectedProjectRootsMutex;
diff --git a/clang-tools-extra/clangd/ModulesBuilder.h b/clang-tools-extra/clangd/ModulesBuilder.h
index b0e110b92b6a7..f91e2a4720c46 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.h
+++ b/clang-tools-extra/clangd/ModulesBuilder.h
@@ -81,7 +81,7 @@ class PrerequisiteModules {
 
 /// This class handles building module files for a given source file.
 ///
-/// In the future, we want the class to manage the module files acorss
+/// In the future, we want the class to manage the module files across
 /// different versions and different source files.
 class ModulesBuilder {
 public:

>From 2976b3cc5cb987a5e6c3b658a8c514dcef2c8b26 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Wed, 13 May 2026 22:13:11 -0700
Subject: [PATCH 02/12] Create build database clone from json compilation
 database

---
 clang-tools-extra/clangd/ClangdLSPServer.cpp  |  56 ++--
 .../clangd/GlobalCompilationDatabase.cpp      |  37 ++-
 .../include/clang/Tooling/JSONBuildDatabase.h | 137 ++++++++
 clang/lib/Tooling/CMakeLists.txt              |   1 +
 clang/lib/Tooling/CompilationDatabase.cpp     |  35 +-
 clang/lib/Tooling/JSONBuildDatabase.cpp       | 307 ++++++++++++++++++
 clang/lib/Tooling/JSONCompilationDatabase.cpp |  58 ++--
 7 files changed, 556 insertions(+), 75 deletions(-)
 create mode 100644 clang/include/clang/Tooling/JSONBuildDatabase.h
 create mode 100644 clang/lib/Tooling/JSONBuildDatabase.cpp

diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 04f58ab6446d1..9d08352479106 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -136,10 +136,9 @@ CodeAction toCodeAction(const Fix &F, const URIForFile &File,
     Edit.textDocument = VersionedTextDocumentIdentifier{{File}, Version};
     for (const auto &E : F.Edits)
       Edit.edits.push_back(
-          {E.range, E.newText,
-           SupportChangeAnnotation ? E.annotationId : ""});
+          {E.range, E.newText, SupportChangeAnnotation ? E.annotationId : ""});
     if (SupportChangeAnnotation) {
-      for (const auto &[AID, Annotation]: F.Annotations)
+      for (const auto &[AID, Annotation] : F.Annotations)
         Action.edit->changeAnnotations[AID] = Annotation;
     }
   }
@@ -908,24 +907,24 @@ void ClangdLSPServer::onRename(const RenameParams &Params,
   if (!Server->getDraft(File))
     return Reply(llvm::make_error<LSPError>(
         "onRename called for non-added file", ErrorCode::InvalidParams));
-  Server->rename(File, Params.position, Params.newName, Opts.Rename,
-                 [File, Params, Reply = std::move(Reply),
-                  this](llvm::Expected<RenameResult> R) mutable {
-                   if (!R)
-                     return Reply(R.takeError());
-                   if (auto Err = validateEdits(*Server, R->GlobalChanges))
-                     return Reply(std::move(Err));
-                   WorkspaceEdit Result;
-                   // FIXME: use documentChanges if SupportDocumentChanges is
-                   // true.
-                   Result.changes.emplace();
-                   for (const auto &Rep : R->GlobalChanges) {
-                     (*Result
-                           .changes)[URI::createFile(Rep.first()).toString()] =
-                         Rep.second.asTextEdits();
-                   }
-                   Reply(Result);
-                 });
+  Server->rename(
+      File, Params.position, Params.newName, Opts.Rename,
+      [File, Params, Reply = std::move(Reply),
+       this](llvm::Expected<RenameResult> R) mutable {
+        if (!R)
+          return Reply(R.takeError());
+        if (auto Err = validateEdits(*Server, R->GlobalChanges))
+          return Reply(std::move(Err));
+        WorkspaceEdit Result;
+        // FIXME: use documentChanges if SupportDocumentChanges is
+        // true.
+        Result.changes.emplace();
+        for (const auto &Rep : R->GlobalChanges) {
+          (*Result.changes)[URI::createFile(Rep.first()).toString()] =
+              Rep.second.asTextEdits();
+        }
+        Reply(Result);
+      });
 }
 
 void ClangdLSPServer::onDocumentDidClose(
@@ -1069,7 +1068,7 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
   std::map<ClangdServer::DiagRef, clangd::Diagnostic> ToLSPDiags;
   ClangdServer::CodeActionInputs Inputs;
 
-  for (const auto& LSPDiag : Params.context.diagnostics) {
+  for (const auto &LSPDiag : Params.context.diagnostics) {
     if (auto DiagRef = getDiagRef(File.file(), LSPDiag)) {
       ToLSPDiags[*DiagRef] = LSPDiag;
       Inputs.Diagnostics.push_back(*DiagRef);
@@ -1078,13 +1077,9 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
   Inputs.File = File.file();
   Inputs.Selection = Params.range;
   Inputs.RequestedActionKinds = Params.context.only;
-  Inputs.TweakFilter = [this](const Tweak &T) {
-    return Opts.TweakFilter(T);
-  };
-  auto CB = [this,
-             Reply = std::move(Reply),
-             ToLSPDiags = std::move(ToLSPDiags), File,
-             Selection = Params.range](
+  Inputs.TweakFilter = [this](const Tweak &T) { return Opts.TweakFilter(T); };
+  auto CB = [this, Reply = std::move(Reply), ToLSPDiags = std::move(ToLSPDiags),
+             File, Selection = Params.range](
                 llvm::Expected<ClangdServer::CodeActionResult> Fixits) mutable {
     if (!Fixits)
       return Reply(Fixits.takeError());
@@ -1093,8 +1088,7 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
     for (const auto &QF : Fixits->QuickFixes) {
       CAs.push_back(toCodeAction(QF.F, File, Version, SupportsDocumentChanges,
                                  SupportsChangeAnnotation));
-      if (auto It = ToLSPDiags.find(QF.Diag);
-          It != ToLSPDiags.end()) {
+      if (auto It = ToLSPDiags.find(QF.Diag); It != ToLSPDiags.end()) {
         CAs.back().diagnostics = {It->second};
       }
     }
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index adb771ecbbaad..8ba66ca41d312 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -18,6 +18,7 @@
 #include "clang/Tooling/ArgumentsAdjusters.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "clang/Tooling/JSONBuildDatabase.h"
 #include "clang/Tooling/JSONCompilationDatabase.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/PointerIntPair.h"
@@ -133,6 +134,8 @@ class DirectoryBasedGlobalCompilationDatabase::DirectoryCache {
   // shared_ptr so we can overwrite this when callers are still using the CDB.
   std::shared_ptr<tooling::CompilationDatabase> CDB;
   // File metadata for the CDB files we support tracking directly.
+  CachedFile BuildDatabaseJson;
+  CachedFile BuildBuildDatabaseJson;
   CachedFile CompileCommandsJson;
   CachedFile BuildCompileCommandsJson;
   CachedFile CompileFlagsTxt;
@@ -146,7 +149,9 @@ class DirectoryBasedGlobalCompilationDatabase::DirectoryCache {
 
 public:
   DirectoryCache(llvm::StringRef Path)
-      : CompileCommandsJson(Path, "compile_commands.json"),
+      : BuildDatabaseJson(Path, "build_database.json"),
+        BuildBuildDatabaseJson(Path, "build/build_database.json"),
+        CompileCommandsJson(Path, "compile_commands.json"),
         BuildCompileCommandsJson(Path, "build/compile_commands.json"),
         CompileFlagsTxt(Path, "compile_flags.txt"), Path(Path) {
     assert(llvm::sys::path::is_absolute(Path));
@@ -247,7 +252,25 @@ DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
 
 // Adapt CDB-loading functions to a common interface for DirectoryCache::load().
 static std::unique_ptr<tooling::CompilationDatabase>
-parseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
+parseBuildDatabaseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
+  if (auto CDB = tooling::JSONCompilationDatabase::loadFromBuffer(
+          Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
+    // FS used for expanding response files.
+    // FIXME: ExpandResponseFilesDatabase appears not to provide the usual
+    // thread-safety guarantees, as the access to FS is not locked!
+    // For now, use the real FS, which is known to be threadsafe (if we don't
+    // use/change working directory, which ExpandResponseFilesDatabase doesn't).
+    // NOTE: response files have to be expanded before inference because
+    // inference needs full command line to check/fix driver mode and file type.
+    auto FS = llvm::vfs::getRealFileSystem();
+    return tooling::inferMissingCompileCommands(
+        expandResponseFiles(std::move(CDB), std::move(FS)));
+  }
+  return nullptr;
+}
+static std::unique_ptr<tooling::CompilationDatabase>
+parseComplilationCommandsJSON(PathRef Path, llvm::StringRef Data,
+                              std::string &Error) {
   if (auto CDB = tooling::JSONCompilationDatabase::loadFromBuffer(
           Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
     // FS used for expanding response files.
@@ -286,9 +309,12 @@ bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
         /*Data*/ llvm::StringRef,
         /*ErrorMsg*/ std::string &);
   };
-  for (const auto &Entry : {CDBFile{&CompileCommandsJson, parseJSON},
-                            CDBFile{&BuildCompileCommandsJson, parseJSON},
-                            CDBFile{&CompileFlagsTxt, parseFixed}}) {
+  for (const auto &Entry :
+       {CDBFile{&BuildDatabaseJson, parseBuildDatabaseJSON},
+        CDBFile{&BuildBuildDatabaseJson, parseBuildDatabaseJSON},
+        CDBFile{&CompileCommandsJson, parseComplilationCommandsJSON},
+        CDBFile{&BuildCompileCommandsJson, parseComplilationCommandsJSON},
+        CDBFile{&CompileFlagsTxt, parseFixed}}) {
     bool Active = ActiveCachedFile == Entry.File;
     auto Loaded = Entry.File->load(FS, Active);
     switch (Loaded.Result) {
@@ -333,6 +359,7 @@ bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(
        tooling::CompilationDatabasePluginRegistry::entries()) {
     // Avoid duplicating the special cases handled above.
     if (Entry.getName() == "fixed-compilation-database" ||
+        Entry.getName() == "json-build-database" ||
         Entry.getName() == "json-compilation-database")
       continue;
     auto Plugin = Entry.instantiate();
diff --git a/clang/include/clang/Tooling/JSONBuildDatabase.h b/clang/include/clang/Tooling/JSONBuildDatabase.h
new file mode 100644
index 0000000000000..83680dad28a8e
--- /dev/null
+++ b/clang/include/clang/Tooling/JSONBuildDatabase.h
@@ -0,0 +1,137 @@
+//===- JSONBuildDatabase.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  The JSONBuildDatabase finds build databases supplied as a file
+//  'compile_commands.json'.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_JSONBUILDDATABASE_H
+#define LLVM_CLANG_TOOLING_JSONBUILDDATABASE_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/FileMatchTrie.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// A JSON based build database.
+///
+/// JSON compilation database files must contain a list of JSON objects which
+/// provide the command lines in the attributes 'directory', 'command',
+/// 'arguments' and 'file':
+/// [
+///   { "directory": "<working directory of the compile>",
+///     "command": "<compile command line>",
+///     "file": "<path to source file>"
+///   },
+///   { "directory": "<working directory of the compile>",
+///     "arguments": ["<raw>", "<command>" "<line>" "<parameters>"],
+///     "file": "<path to source file>"
+///   },
+///   ...
+/// ]
+/// Each object entry defines one compile action. The specified file is
+/// considered to be the main source file for the translation unit.
+///
+/// 'command' is a full command line that will be unescaped.
+///
+/// 'arguments' is a list of command line arguments that will not be unescaped.
+///
+/// JSON build databases can for example be generated in CMake projects
+/// by setting the flag -DCMAKE_EXPORT_BUILD_DATABASE.
+class JSONBuildDatabase : public CompilationDatabase {
+public:
+  /// Loads a JSON build database from the specified file.
+  ///
+  /// Returns NULL and sets ErrorMessage if the database could not be
+  /// loaded from the given file.
+  static std::unique_ptr<JSONBuildDatabase>
+  loadFromFile(StringRef FilePath, std::string &ErrorMessage);
+
+  /// Loads a JSON build database from a data buffer.
+  ///
+  /// Returns NULL and sets ErrorMessage if the database could not be loaded.
+  static std::unique_ptr<JSONBuildDatabase>
+  loadFromBuffer(StringRef DatabaseString, std::string &ErrorMessage);
+
+  /// Returns all compile commands in which the specified file was
+  /// compiled.
+  ///
+  /// FIXME: Currently FilePath must be an absolute path inside the
+  /// source directory which does not have symlinks resolved.
+  std::vector<CompileCommand>
+  getCompileCommands(StringRef FilePath) const override;
+
+  /// Returns the list of all files available in the build database.
+  ///
+  /// These are the 'file' entries of the JSON objects.
+  std::vector<std::string> getAllFiles() const override;
+
+  /// Returns all compile commands for all the files in the build
+  /// database.
+  std::vector<CompileCommand> getAllCompileCommands() const override;
+
+private:
+  /// Constructs a JSON build database on a memory buffer.
+  JSONBuildDatabase(std::unique_ptr<llvm::MemoryBuffer> Database)
+      : Database(std::move(Database)),
+        YAMLStream(this->Database->getBuffer(), SM) {}
+
+  /// Parses the database file and creates the index.
+  ///
+  /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
+  /// failed.
+  bool parse(std::string &ErrorMessage);
+
+  // Tuple (directory, filename, commandline, output) where 'commandline'
+  // points to the corresponding scalar nodes in the YAML stream.
+  // If the command line contains a single argument, it is a shell-escaped
+  // command line.
+  // Otherwise, each entry in the command line vector is a literal
+  // argument to the compiler.
+  // The output field may be a nullptr.
+  using CompileCommandRef =
+      std::tuple<llvm::yaml::ScalarNode *, llvm::yaml::ScalarNode *,
+                 std::vector<llvm::yaml::ScalarNode *>,
+                 llvm::yaml::ScalarNode *>;
+
+  /// Converts the given array of CompileCommandRefs to CompileCommands.
+  void getCommands(ArrayRef<CompileCommandRef> CommandsRef,
+                   std::vector<CompileCommand> &Commands) const;
+
+  // Maps file paths to the compile command lines for that file.
+  llvm::StringMap<std::vector<CompileCommandRef>> IndexByFile;
+
+  /// All the compile commands in the order that they were provided in the
+  /// JSON stream.
+  std::vector<CompileCommandRef> AllCommands;
+
+  FileMatchTrie MatchTrie;
+
+  std::unique_ptr<llvm::MemoryBuffer> Database;
+  llvm::SourceMgr SM;
+  llvm::yaml::Stream YAMLStream;
+};
+
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLING_JSONBUILDDATABASE_H
diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index 0972ecb08437f..00b27d6d61cfe 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangTooling
   FixIt.cpp
   GuessTargetAndModeCompilationDatabase.cpp
   InterpolatingCompilationDatabase.cpp
+  JSONBuildDatabase.cpp
   JSONCompilationDatabase.cpp
   LocateToolCompilationDatabase.cpp
   Refactoring.cpp
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index 4070bb81c6f74..187e1223f5cef 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -84,7 +84,8 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
 
     if (!HasErrorMessage) {
       ErrorStream << "No compilation database found in " << Directory.str()
-                  << " or any parent directory\n" << LoadErrorMessage;
+                  << " or any parent directory\n"
+                  << LoadErrorMessage;
       HasErrorMessage = true;
     }
 
@@ -105,7 +106,8 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
 
   if (!DB)
     ErrorMessage = ("Could not auto-detect compilation database for file \"" +
-                   SourceFile + "\"\n" + ErrorMessage).str();
+                    SourceFile + "\"\n" + ErrorMessage)
+                       .str();
   return DB;
 }
 
@@ -118,8 +120,10 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
       findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
 
   if (!DB)
-    ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
-                   SourceDir + "\"\n" + ErrorMessage).str();
+    ErrorMessage =
+        ("Could not auto-detect compilation database from directory \"" +
+         SourceDir + "\"\n" + ErrorMessage)
+            .str();
   return DB;
 }
 
@@ -141,9 +145,7 @@ namespace {
 struct CompileJobAnalyzer {
   SmallVector<std::string, 2> Inputs;
 
-  void run(const driver::Action *A) {
-    runImpl(A, false);
-  }
+  void run(const driver::Action *A) { runImpl(A, false); }
 
 private:
   void runImpl(const driver::Action *A, bool Collect) {
@@ -198,7 +200,7 @@ class UnusedInputDiagConsumer : public DiagnosticConsumer {
 // They are not used for syntax checking, and could confuse targets
 // which don't support these options.
 struct FilterUnusedFlags {
-  bool operator() (StringRef S) {
+  bool operator()(StringRef S) {
     return (S == "-no-integrated-as") || S.starts_with("-Wa,");
   }
 };
@@ -366,11 +368,10 @@ FixedCompilationDatabase::loadFromBuffer(StringRef Directory, StringRef Data,
 FixedCompilationDatabase::FixedCompilationDatabase(
     const Twine &Directory, ArrayRef<std::string> CommandLine) {
   std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
-  ToolCommandLine.insert(ToolCommandLine.end(),
-                         CommandLine.begin(), CommandLine.end());
+  ToolCommandLine.insert(ToolCommandLine.end(), CommandLine.begin(),
+                         CommandLine.end());
   CompileCommands.emplace_back(Directory, StringRef(),
-                               std::move(ToolCommandLine),
-                               StringRef());
+                               std::move(ToolCommandLine), StringRef());
 }
 
 std::vector<CompileCommand>
@@ -395,15 +396,19 @@ class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
 } // namespace
 
 static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
-X("fixed-compilation-database", "Reads plain-text flags file");
+    X("fixed-compilation-database", "Reads plain-text flags file");
 
 namespace clang {
 namespace tooling {
 
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the JSONCompilationDatabasePlugin.
-extern volatile int JSONAnchorSource;
-[[maybe_unused]] static int JSONAnchorDest = JSONAnchorSource;
+extern volatile int JSONBuildAnchorSource;
+[[maybe_unused]] static int JSONBuildAnchorDest = JSONBuildAnchorSource;
+
+extern volatile int JSONCompilationAnchorSource;
+[[maybe_unused]] static int JSONCompilationAnchorDest =
+    JSONCompilationAnchorSource;
 
 } // namespace tooling
 } // namespace clang
diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
new file mode 100644
index 0000000000000..efa7eb063510b
--- /dev/null
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -0,0 +1,307 @@
+//===- JSONBuildDatabase.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file contains the implementation of the JSONBuildDatabase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/JSONBuildDatabase.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include <cassert>
+#include <memory>
+#include <optional>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+// This plugin locates a nearby compile_command.json file, and also infers
+// compile commands for files not present in the database.
+class JSONBuildDatabasePlugin : public CompilationDatabasePlugin {
+  std::unique_ptr<CompilationDatabase>
+  loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
+    SmallString<1024> JSONDatabasePath(Directory);
+    llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+    auto Base = JSONBuildDatabase::loadFromFile(JSONDatabasePath, ErrorMessage);
+    return Base ? inferTargetAndDriverMode(
+                      inferMissingCompileCommands(expandResponseFiles(
+                          std::move(Base), llvm::vfs::getRealFileSystem())))
+                : nullptr;
+  }
+};
+
+} // namespace
+
+// Register the JSONBuildDatabasePlugin with the
+// CompilationDatabasePluginRegistry using this statically initialized variable.
+static CompilationDatabasePluginRegistry::Add<JSONBuildDatabasePlugin>
+    X("json-build-database", "Reads JSON formatted build databases");
+
+namespace clang {
+namespace tooling {
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the JSONBuildDatabasePlugin.
+volatile int JSONBuildAnchorSource = 0;
+
+} // namespace tooling
+} // namespace clang
+
+std::unique_ptr<JSONBuildDatabase>
+JSONBuildDatabase::loadFromFile(StringRef FilePath, std::string &ErrorMessage) {
+  // Don't mmap: if we're a long-lived process, the build system may overwrite.
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
+      llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/false,
+                                  /*RequiresNullTerminator=*/true,
+                                  /*IsVolatile=*/true);
+  if (std::error_code Result = DatabaseBuffer.getError()) {
+    ErrorMessage = "Error while opening JSON database: " + Result.message();
+    return nullptr;
+  }
+  std::unique_ptr<JSONBuildDatabase> Database(
+      new JSONBuildDatabase(std::move(*DatabaseBuffer)));
+  if (!Database->parse(ErrorMessage))
+    return nullptr;
+  return Database;
+}
+
+std::unique_ptr<JSONBuildDatabase>
+JSONBuildDatabase::loadFromBuffer(StringRef DatabaseString,
+                                  std::string &ErrorMessage) {
+  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
+      llvm::MemoryBuffer::getMemBufferCopy(DatabaseString));
+  std::unique_ptr<JSONBuildDatabase> Database(
+      new JSONBuildDatabase(std::move(DatabaseBuffer)));
+  if (!Database->parse(ErrorMessage))
+    return nullptr;
+  return Database;
+}
+
+std::vector<CompileCommand>
+JSONBuildDatabase::getCompileCommands(StringRef FilePath) const {
+  SmallString<128> NativeFilePath;
+  llvm::sys::path::native(FilePath, NativeFilePath);
+
+  std::string Error;
+  llvm::raw_string_ostream ES(Error);
+  StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
+  if (Match.empty())
+    return {};
+  const auto CommandsRefI = IndexByFile.find(Match);
+  if (CommandsRefI == IndexByFile.end())
+    return {};
+  std::vector<CompileCommand> Commands;
+  getCommands(CommandsRefI->getValue(), Commands);
+  return Commands;
+}
+
+std::vector<std::string> JSONBuildDatabase::getAllFiles() const {
+  std::vector<std::string> Result;
+  for (const auto &CommandRef : IndexByFile)
+    Result.push_back(CommandRef.first().str());
+  return Result;
+}
+
+std::vector<CompileCommand> JSONBuildDatabase::getAllCompileCommands() const {
+  std::vector<CompileCommand> Commands;
+  getCommands(AllCommands, Commands);
+  return Commands;
+}
+
+static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
+  Name.consume_back(".exe");
+  return Name;
+}
+
+// There are compiler-wrappers (ccache, distcc) that take the "real"
+// compiler as an argument, e.g. distcc gcc -O3 foo.c.
+// These end up in compile_commands.json when people set CC="distcc gcc".
+// Clang's driver doesn't understand this, so we need to unwrap.
+static bool unwrapCommand(std::vector<std::string> &Args) {
+  if (Args.size() < 2)
+    return false;
+  StringRef Wrapper =
+      stripExecutableExtension(llvm::sys::path::filename(Args.front()));
+  if (Wrapper == "distcc" || Wrapper == "ccache" || Wrapper == "sccache") {
+    // Most of these wrappers support being invoked 3 ways:
+    // `distcc g++ file.c` This is the mode we're trying to match.
+    //                     We need to drop `distcc`.
+    // `distcc file.c`     This acts like compiler is cc or similar.
+    //                     Clang's driver can handle this, no change needed.
+    // `g++ file.c`        g++ is a symlink to distcc.
+    //                     We don't even notice this case, and all is well.
+    //
+    // We need to distinguish between the first and second case.
+    // The wrappers themselves don't take flags, so Args[1] is a compiler flag,
+    // an input file, or a compiler. Inputs have extensions, compilers don't.
+    bool HasCompiler =
+        (Args[1][0] != '-') &&
+        !llvm::sys::path::has_extension(stripExecutableExtension(Args[1]));
+    if (HasCompiler) {
+      Args.erase(Args.begin());
+      return true;
+    }
+    // If !HasCompiler, wrappers act like GCC. Fine: so do we.
+  }
+  return false;
+}
+
+static std::vector<std::string>
+nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
+  SmallString<1024> Storage;
+  std::vector<std::string> Arguments;
+  for (const auto *Node : Nodes)
+    Arguments.push_back(std::string(Node->getValue(Storage)));
+  // There may be multiple wrappers: using distcc and ccache together is common.
+  while (unwrapCommand(Arguments))
+    ;
+  return Arguments;
+}
+
+void JSONBuildDatabase::getCommands(
+    ArrayRef<CompileCommandRef> CommandsRef,
+    std::vector<CompileCommand> &Commands) const {
+  for (const auto &CommandRef : CommandsRef) {
+    SmallString<8> DirectoryStorage;
+    SmallString<32> FilenameStorage;
+    SmallString<32> OutputStorage;
+    auto Output = std::get<3>(CommandRef);
+    Commands.emplace_back(std::get<0>(CommandRef)->getValue(DirectoryStorage),
+                          std::get<1>(CommandRef)->getValue(FilenameStorage),
+                          nodeToCommandLine(std::get<2>(CommandRef)),
+                          Output ? Output->getValue(OutputStorage) : "");
+  }
+}
+
+bool JSONBuildDatabase::parse(std::string &ErrorMessage) {
+  llvm::yaml::document_iterator I = YAMLStream.begin();
+  if (I == YAMLStream.end()) {
+    ErrorMessage = "Error while parsing YAML.";
+    return false;
+  }
+  llvm::yaml::Node *Root = I->getRoot();
+  if (!Root) {
+    ErrorMessage = "Error while parsing YAML.";
+    return false;
+  }
+  auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
+  if (!Array) {
+    ErrorMessage = "Expected array.";
+    return false;
+  }
+  for (auto &NextObject : *Array) {
+    auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
+    if (!Object) {
+      ErrorMessage = "Expected object.";
+      return false;
+    }
+    llvm::yaml::ScalarNode *Directory = nullptr;
+    std::optional<std::vector<llvm::yaml::ScalarNode *>> Command;
+    llvm::yaml::ScalarNode *File = nullptr;
+    llvm::yaml::ScalarNode *Output = nullptr;
+    for (auto &NextKeyValue : *Object) {
+      auto *KeyString =
+          dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+      if (!KeyString) {
+        ErrorMessage = "Expected strings as key.";
+        return false;
+      }
+      SmallString<10> KeyStorage;
+      StringRef KeyValue = KeyString->getValue(KeyStorage);
+      llvm::yaml::Node *Value = NextKeyValue.getValue();
+      if (!Value) {
+        ErrorMessage = "Expected value.";
+        return false;
+      }
+      auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (KeyValue == "arguments") {
+        if (!SequenceString) {
+          ErrorMessage = "Expected sequence as value.";
+          return false;
+        }
+        Command = std::vector<llvm::yaml::ScalarNode *>();
+        for (auto &Argument : *SequenceString) {
+          auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
+          if (!Scalar) {
+            ErrorMessage = "Only strings are allowed in 'arguments'.";
+            return false;
+          }
+          Command->push_back(Scalar);
+        }
+      } else {
+        if (!ValueString) {
+          ErrorMessage = "Expected string as value.";
+          return false;
+        }
+        if (KeyValue == "directory") {
+          Directory = ValueString;
+        } else if (KeyValue == "command") {
+          if (!Command)
+            Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
+        } else if (KeyValue == "file") {
+          File = ValueString;
+        } else if (KeyValue == "output") {
+          Output = ValueString;
+        } else {
+          ErrorMessage =
+              ("Unknown key: \"" + KeyString->getRawValue() + "\"").str();
+          return false;
+        }
+      }
+    }
+    if (!File) {
+      ErrorMessage = "Missing key: \"file\".";
+      return false;
+    }
+    if (!Command) {
+      ErrorMessage = "Missing key: \"command\" or \"arguments\".";
+      return false;
+    }
+    if (!Directory) {
+      ErrorMessage = "Missing key: \"directory\".";
+      return false;
+    }
+    SmallString<8> FileStorage;
+    StringRef FileName = File->getValue(FileStorage);
+    SmallString<128> NativeFilePath;
+    if (llvm::sys::path::is_relative(FileName)) {
+      SmallString<8> DirectoryStorage;
+      SmallString<128> AbsolutePath(Directory->getValue(DirectoryStorage));
+      llvm::sys::path::append(AbsolutePath, FileName);
+      llvm::sys::path::native(AbsolutePath, NativeFilePath);
+    } else {
+      llvm::sys::path::native(FileName, NativeFilePath);
+    }
+    llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
+    auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
+    IndexByFile[NativeFilePath].push_back(Cmd);
+    AllCommands.push_back(Cmd);
+    MatchTrie.insert(NativeFilePath);
+  }
+  return true;
+}
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 0efa75970d986..9155b01f3fe13 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -45,9 +45,9 @@ namespace {
 /// Assumes \-escaping for quoted arguments (see the documentation of
 /// unescapeCommandLine(...)).
 class CommandLineArgumentParser {
- public:
+public:
   CommandLineArgumentParser(StringRef CommandLine)
-      : Input(CommandLine), Position(Input.begin()-1) {}
+      : Input(CommandLine), Position(Input.begin() - 1) {}
 
   std::vector<std::string> parse() {
     bool HasMoreInput = true;
@@ -59,46 +59,56 @@ class CommandLineArgumentParser {
     return CommandLine;
   }
 
- private:
+private:
   // All private methods return true if there is more input available.
 
   bool parseStringInto(std::string &String) {
     do {
       if (*Position == '"') {
-        if (!parseDoubleQuotedStringInto(String)) return false;
+        if (!parseDoubleQuotedStringInto(String))
+          return false;
       } else if (*Position == '\'') {
-        if (!parseSingleQuotedStringInto(String)) return false;
+        if (!parseSingleQuotedStringInto(String))
+          return false;
       } else {
-        if (!parseFreeStringInto(String)) return false;
+        if (!parseFreeStringInto(String))
+          return false;
       }
     } while (*Position != ' ');
     return true;
   }
 
   bool parseDoubleQuotedStringInto(std::string &String) {
-    if (!next()) return false;
+    if (!next())
+      return false;
     while (*Position != '"') {
-      if (!skipEscapeCharacter()) return false;
+      if (!skipEscapeCharacter())
+        return false;
       String.push_back(*Position);
-      if (!next()) return false;
+      if (!next())
+        return false;
     }
     return next();
   }
 
   bool parseSingleQuotedStringInto(std::string &String) {
-    if (!next()) return false;
+    if (!next())
+      return false;
     while (*Position != '\'') {
       String.push_back(*Position);
-      if (!next()) return false;
+      if (!next())
+        return false;
     }
     return next();
   }
 
   bool parseFreeStringInto(std::string &String) {
     do {
-      if (!skipEscapeCharacter()) return false;
+      if (!skipEscapeCharacter())
+        return false;
       String.push_back(*Position);
-      if (!next()) return false;
+      if (!next())
+        return false;
     } while (*Position != ' ' && *Position != '"' && *Position != '\'');
     return true;
   }
@@ -112,7 +122,8 @@ class CommandLineArgumentParser {
 
   bool nextNonWhitespace() {
     do {
-      if (!next()) return false;
+      if (!next())
+        return false;
     } while (*Position == ' ');
     return true;
   }
@@ -172,14 +183,15 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
 // Register the JSONCompilationDatabasePlugin with the
 // CompilationDatabasePluginRegistry using this statically initialized variable.
 static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
-X("json-compilation-database", "Reads JSON formatted compilation databases");
+    X("json-compilation-database",
+      "Reads JSON formatted compilation databases");
 
 namespace clang {
 namespace tooling {
 
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the JSONCompilationDatabasePlugin.
-volatile int JSONAnchorSource = 0;
+volatile int JSONCompilationAnchorSource = 0;
 
 } // namespace tooling
 } // namespace clang
@@ -235,8 +247,7 @@ JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
   return Commands;
 }
 
-std::vector<std::string>
-JSONCompilationDatabase::getAllFiles() const {
+std::vector<std::string> JSONCompilationDatabase::getAllFiles() const {
   std::vector<std::string> Result;
   for (const auto &CommandRef : IndexByFile)
     Result.push_back(CommandRef.first().str());
@@ -312,11 +323,10 @@ void JSONCompilationDatabase::getCommands(
     SmallString<32> FilenameStorage;
     SmallString<32> OutputStorage;
     auto Output = std::get<3>(CommandRef);
-    Commands.emplace_back(
-        std::get<0>(CommandRef)->getValue(DirectoryStorage),
-        std::get<1>(CommandRef)->getValue(FilenameStorage),
-        nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
-        Output ? Output->getValue(OutputStorage) : "");
+    Commands.emplace_back(std::get<0>(CommandRef)->getValue(DirectoryStorage),
+                          std::get<1>(CommandRef)->getValue(FilenameStorage),
+                          nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
+                          Output ? Output->getValue(OutputStorage) : "");
   }
 }
 
@@ -346,7 +356,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
     std::optional<std::vector<llvm::yaml::ScalarNode *>> Command;
     llvm::yaml::ScalarNode *File = nullptr;
     llvm::yaml::ScalarNode *Output = nullptr;
-    for (auto& NextKeyValue : *Object) {
+    for (auto &NextKeyValue : *Object) {
       auto *KeyString =
           dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
       if (!KeyString) {

>From 1da7510749db19f6f5f73c78554c343bac64e499 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Sun, 17 May 2026 19:29:59 -0700
Subject: [PATCH 03/12] Parse full build_database

---
 .../clangd/GlobalCompilationDatabase.cpp      |   3 +-
 .../include/clang/Tooling/JSONBuildDatabase.h |   3 +
 clang/lib/Tooling/JSONBuildDatabase.cpp       | 313 ++++++++++++++----
 3 files changed, 247 insertions(+), 72 deletions(-)

diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 8ba66ca41d312..11205a1b7c646 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -253,8 +253,7 @@ DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
 // Adapt CDB-loading functions to a common interface for DirectoryCache::load().
 static std::unique_ptr<tooling::CompilationDatabase>
 parseBuildDatabaseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
-  if (auto CDB = tooling::JSONCompilationDatabase::loadFromBuffer(
-          Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
+  if (auto CDB = tooling::JSONBuildDatabase::loadFromBuffer(Data, Error)) {
     // FS used for expanding response files.
     // FIXME: ExpandResponseFilesDatabase appears not to provide the usual
     // thread-safety guarantees, as the access to FS is not locked!
diff --git a/clang/include/clang/Tooling/JSONBuildDatabase.h b/clang/include/clang/Tooling/JSONBuildDatabase.h
index 83680dad28a8e..403aae91a19bd 100644
--- a/clang/include/clang/Tooling/JSONBuildDatabase.h
+++ b/clang/include/clang/Tooling/JSONBuildDatabase.h
@@ -100,6 +100,9 @@ class JSONBuildDatabase : public CompilationDatabase {
   /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
   /// failed.
   bool parse(std::string &ErrorMessage);
+  bool parseRoot(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
+  bool parseSet(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
+  bool parseTU(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
 
   // Tuple (directory, filename, commandline, output) where 'commandline'
   // points to the corresponding scalar nodes in the YAML stream.
diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index efa7eb063510b..1d631d6b928dd 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -30,8 +30,11 @@
 #include <cassert>
 #include <memory>
 #include <optional>
+#include <signal.h>
 #include <string>
 #include <system_error>
+#include <thread>
+#include <unistd.h>
 #include <utility>
 #include <vector>
 
@@ -208,100 +211,270 @@ bool JSONBuildDatabase::parse(std::string &ErrorMessage) {
     ErrorMessage = "Error while parsing YAML.";
     return false;
   }
-  auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
-  if (!Array) {
-    ErrorMessage = "Expected array.";
+  auto *RootObject = dyn_cast<llvm::yaml::MappingNode>(Root);
+  if (!RootObject) {
+    ErrorMessage = "Expected object at root.";
     return false;
   }
-  for (auto &NextObject : *Array) {
-    auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
-    if (!Object) {
-      ErrorMessage = "Expected object.";
+  return parseRoot(ErrorMessage, RootObject);
+}
+
+bool JSONBuildDatabase::parseRoot(std::string &ErrorMessage,
+                                  llvm::yaml::MappingNode *RootObject) {
+  llvm::yaml::ScalarNode *Version = nullptr;
+  llvm::yaml::ScalarNode *Revision = nullptr;
+  llvm::yaml::SequenceNode *Sets = nullptr;
+  for (auto &NextKeyValue : *RootObject) {
+    auto *KeyString =
+        dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+    if (!KeyString) {
+      ErrorMessage = "Expected strings as key.";
       return false;
     }
-    llvm::yaml::ScalarNode *Directory = nullptr;
-    std::optional<std::vector<llvm::yaml::ScalarNode *>> Command;
-    llvm::yaml::ScalarNode *File = nullptr;
-    llvm::yaml::ScalarNode *Output = nullptr;
-    for (auto &NextKeyValue : *Object) {
-      auto *KeyString =
-          dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
-      if (!KeyString) {
-        ErrorMessage = "Expected strings as key.";
+    SmallString<10> KeyStorage;
+    StringRef KeyValue = KeyString->getValue(KeyStorage);
+    llvm::yaml::Node *Value = NextKeyValue.getValue();
+    if (!Value) {
+      ErrorMessage = "Expected value.";
+      return false;
+    }
+    if (KeyValue == "version") {
+      Version = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Version) {
+        ErrorMessage = "Expected string as value for \"version\".";
+        return false;
+      }
+    } else if (KeyValue == "revision") {
+      Revision = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Revision) {
+        ErrorMessage = "Expected string as value for \"revision\".";
         return false;
       }
-      SmallString<10> KeyStorage;
-      StringRef KeyValue = KeyString->getValue(KeyStorage);
-      llvm::yaml::Node *Value = NextKeyValue.getValue();
-      if (!Value) {
-        ErrorMessage = "Expected value.";
+    } else if (KeyValue == "sets") {
+      Sets = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!Sets) {
+        ErrorMessage = "Expected array as value for \"sets\".";
         return false;
       }
-      auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
-      auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
-      if (KeyValue == "arguments") {
-        if (!SequenceString) {
-          ErrorMessage = "Expected sequence as value.";
+      for (auto &NextObject : *Sets) {
+        auto *SetObject = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
+        if (!RootObject) {
+          ErrorMessage = "Expected sets item as object.";
           return false;
         }
-        Command = std::vector<llvm::yaml::ScalarNode *>();
-        for (auto &Argument : *SequenceString) {
-          auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
-          if (!Scalar) {
-            ErrorMessage = "Only strings are allowed in 'arguments'.";
-            return false;
-          }
-          Command->push_back(Scalar);
+        if (!parseSet(ErrorMessage, SetObject)) {
+          return false;
         }
-      } else {
-        if (!ValueString) {
-          ErrorMessage = "Expected string as value.";
+      }
+    } else {
+      ErrorMessage =
+          ("Unknown key in root: \"" + KeyString->getRawValue() + "\"").str();
+      return false;
+    }
+  }
+  // Check required fields
+  if (!Version) {
+    ErrorMessage = "Missing key in root: \"version\".";
+    return false;
+  }
+  if (!Sets) {
+    ErrorMessage = "Missing key in root: \"sets\".";
+    return false;
+  }
+  // Check compatible version
+  if (Version->getRawValue() != "1") {
+    ErrorMessage =
+        ("Unsupported version: \"" + Version->getRawValue() + "\"").str();
+    return false;
+  }
+  return true;
+}
+
+bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
+                                 llvm::yaml::MappingNode *SetObject) {
+  llvm::yaml::SequenceNode *BaselineArguments = nullptr;
+  llvm::yaml::ScalarNode *FamilyName = nullptr;
+  llvm::yaml::ScalarNode *Name = nullptr;
+  llvm::yaml::SequenceNode *VisibleSets = nullptr;
+  llvm::yaml::SequenceNode *TUs = nullptr;
+  for (auto &NextKeyValue : *SetObject) {
+    auto *KeyString =
+        dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+    if (!KeyString) {
+      ErrorMessage = "Expected strings as key.";
+      return false;
+    }
+    SmallString<10> KeyStorage;
+    StringRef KeyValue = KeyString->getValue(KeyStorage);
+    llvm::yaml::Node *Value = NextKeyValue.getValue();
+    if (!Value) {
+      ErrorMessage = "Expected value.";
+      return false;
+    }
+    if (KeyValue == "baseline-arguments") {
+      BaselineArguments = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!BaselineArguments) {
+        ErrorMessage = "Expected array as value for \"version\".";
+        return false;
+      }
+    } else if (KeyValue == "family-name") {
+      FamilyName = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!FamilyName) {
+        ErrorMessage = "Expected string as value for \"family-name\".";
+        return false;
+      }
+    } else if (KeyValue == "name") {
+      Name = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Name) {
+        ErrorMessage = "Expected string as value for \"name\".";
+        return false;
+      }
+    } else if (KeyValue == "visible-sets") {
+      VisibleSets = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!VisibleSets) {
+        ErrorMessage = "Expected array as value for \"visible-sets\".";
+        return false;
+      }
+    } else if (KeyValue == "translation-units") {
+      TUs = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!TUs) {
+        ErrorMessage = "Expected array as value for \"translation-units\".";
+        return false;
+      }
+      for (auto &NextObject : *TUs) {
+        auto *TUObject = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
+        if (!TUObject) {
+          ErrorMessage = "Expected translation-units item as object.";
           return false;
         }
-        if (KeyValue == "directory") {
-          Directory = ValueString;
-        } else if (KeyValue == "command") {
-          if (!Command)
-            Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
-        } else if (KeyValue == "file") {
-          File = ValueString;
-        } else if (KeyValue == "output") {
-          Output = ValueString;
-        } else {
-          ErrorMessage =
-              ("Unknown key: \"" + KeyString->getRawValue() + "\"").str();
+        if (!parseTU(ErrorMessage, TUObject)) {
           return false;
         }
       }
-    }
-    if (!File) {
-      ErrorMessage = "Missing key: \"file\".";
+    } else {
+      ErrorMessage =
+          ("Unknown key in set: \"" + KeyString->getRawValue() + "\"").str();
       return false;
     }
-    if (!Command) {
-      ErrorMessage = "Missing key: \"command\" or \"arguments\".";
+  }
+  // Check required fields
+  if (!BaselineArguments) {
+    ErrorMessage = "Missing key in set: \"baseline-arguments\".";
+    return false;
+  }
+  if (!FamilyName) {
+    ErrorMessage = "Missing key in set: \"family-name\".";
+    return false;
+  }
+  if (!Name) {
+    ErrorMessage = "Missing key in set: \"name\".";
+    return false;
+  }
+  if (!TUs) {
+    ErrorMessage = "Missing key in set: \"translation-units\".";
+    return false;
+  }
+  return true;
+}
+
+bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
+                                llvm::yaml::MappingNode *TUObject) {
+  llvm::yaml::SequenceNode *Arguments = nullptr;
+  llvm::yaml::ScalarNode *Language = nullptr;
+  llvm::yaml::SequenceNode *LocalArguments = nullptr;
+  llvm::yaml::ScalarNode *WorkingDirectory = nullptr;
+  llvm::yaml::ScalarNode *Private = nullptr;
+  llvm::yaml::ScalarNode *Source = nullptr;
+  llvm::yaml::ScalarNode *Object = nullptr;
+  llvm::yaml::SequenceNode *Provides = nullptr;
+  llvm::yaml::SequenceNode *Requires = nullptr;
+  for (auto &NextKeyValue : *TUObject) {
+    auto *KeyString =
+        dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+    if (!KeyString) {
+      ErrorMessage = "Expected strings as key.";
       return false;
     }
-    if (!Directory) {
-      ErrorMessage = "Missing key: \"directory\".";
+    SmallString<10> KeyStorage;
+    StringRef KeyValue = KeyString->getValue(KeyStorage);
+    llvm::yaml::Node *Value = NextKeyValue.getValue();
+    if (!Value) {
+      ErrorMessage = "Expected value.";
       return false;
     }
-    SmallString<8> FileStorage;
-    StringRef FileName = File->getValue(FileStorage);
-    SmallString<128> NativeFilePath;
-    if (llvm::sys::path::is_relative(FileName)) {
-      SmallString<8> DirectoryStorage;
-      SmallString<128> AbsolutePath(Directory->getValue(DirectoryStorage));
-      llvm::sys::path::append(AbsolutePath, FileName);
-      llvm::sys::path::native(AbsolutePath, NativeFilePath);
+    if (KeyValue == "arguments") {
+      Arguments = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!Arguments) {
+        ErrorMessage = "Expected array as value for \"arguments\".";
+        return false;
+      }
+    } else if (KeyValue == "language") {
+      Language = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Language) {
+        ErrorMessage = "Expected string as value for \"language\".";
+        return false;
+      }
+    } else if (KeyValue == "local-arguments") {
+      LocalArguments = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!LocalArguments) {
+        ErrorMessage = "Expected array as value for \"local-arguments\".";
+        return false;
+      }
+    } else if (KeyValue == "working-directory") {
+      WorkingDirectory = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!WorkingDirectory) {
+        ErrorMessage = "Expected string as value for \"working-directory\".";
+        return false;
+      }
+    } else if (KeyValue == "private") {
+      Private = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Private) {
+        ErrorMessage = "Expected string as value for \"private\".";
+        return false;
+      }
+    } else if (KeyValue == "source") {
+      Source = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Source) {
+        ErrorMessage = "Expected string as value for \"source\".";
+        return false;
+      }
+    } else if (KeyValue == "object") {
+      Object = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!Object) {
+        ErrorMessage = "Expected string as value for \"object\".";
+        return false;
+      }
+    } else if (KeyValue == "provides") {
+      Provides = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!Provides) {
+        ErrorMessage = "Expected array as value for \"provides\".";
+        return false;
+      }
+    } else if (KeyValue == "requires") {
+      Requires = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      if (!Requires) {
+        ErrorMessage = "Expected array as value for \"requires\".";
+        return false;
+      }
     } else {
-      llvm::sys::path::native(FileName, NativeFilePath);
+      ErrorMessage = ("Unknown key in translation-unit: \"" +
+                      KeyString->getRawValue() + "\"")
+                         .str();
+      return false;
     }
-    llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
-    auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
-    IndexByFile[NativeFilePath].push_back(Cmd);
-    AllCommands.push_back(Cmd);
-    MatchTrie.insert(NativeFilePath);
+  }
+  // Check required fields
+  if (!Source) {
+    ErrorMessage = "Missing key in translation-unit: \"source\".";
+    return false;
+  }
+  if (!Language) {
+    ErrorMessage = "Missing key in translation-unit: \"language\".";
+    return false;
+  }
+  if (!Arguments) {
+    ErrorMessage = "Missing key in translation-unit: \"arguments\".";
+    return false;
   }
   return true;
 }

>From 5c9e9953f0f1210f3b9409b7fa70119a8760e7b8 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Mon, 18 May 2026 17:04:32 -0700
Subject: [PATCH 04/12] Finish parse

---
 clang/lib/Tooling/JSONBuildDatabase.cpp | 43 ++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index 1d631d6b928dd..4c3e75610c989 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -380,13 +380,14 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
 bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
                                 llvm::yaml::MappingNode *TUObject) {
   llvm::yaml::SequenceNode *Arguments = nullptr;
+  std::vector<llvm::yaml::ScalarNode *> Command;
   llvm::yaml::ScalarNode *Language = nullptr;
   llvm::yaml::SequenceNode *LocalArguments = nullptr;
-  llvm::yaml::ScalarNode *WorkingDirectory = nullptr;
+  llvm::yaml::ScalarNode *WorkDirectory = nullptr;
   llvm::yaml::ScalarNode *Private = nullptr;
   llvm::yaml::ScalarNode *Source = nullptr;
   llvm::yaml::ScalarNode *Object = nullptr;
-  llvm::yaml::SequenceNode *Provides = nullptr;
+  llvm::yaml::MappingNode *Provides = nullptr;
   llvm::yaml::SequenceNode *Requires = nullptr;
   for (auto &NextKeyValue : *TUObject) {
     auto *KeyString =
@@ -408,6 +409,14 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
         ErrorMessage = "Expected array as value for \"arguments\".";
         return false;
       }
+      for (auto &Argument : *Arguments) {
+        auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
+        if (!Scalar) {
+          ErrorMessage = "Only strings are allowed in 'arguments'.";
+          return false;
+        }
+        Command.push_back(Scalar);
+      }
     } else if (KeyValue == "language") {
       Language = dyn_cast<llvm::yaml::ScalarNode>(Value);
       if (!Language) {
@@ -420,10 +429,10 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
         ErrorMessage = "Expected array as value for \"local-arguments\".";
         return false;
       }
-    } else if (KeyValue == "working-directory") {
-      WorkingDirectory = dyn_cast<llvm::yaml::ScalarNode>(Value);
-      if (!WorkingDirectory) {
-        ErrorMessage = "Expected string as value for \"working-directory\".";
+    } else if (KeyValue == "work-directory") {
+      WorkDirectory = dyn_cast<llvm::yaml::ScalarNode>(Value);
+      if (!WorkDirectory) {
+        ErrorMessage = "Expected string as value for \"work-directory\".";
         return false;
       }
     } else if (KeyValue == "private") {
@@ -445,9 +454,9 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
         return false;
       }
     } else if (KeyValue == "provides") {
-      Provides = dyn_cast<llvm::yaml::SequenceNode>(Value);
+      Provides = dyn_cast<llvm::yaml::MappingNode>(Value);
       if (!Provides) {
-        ErrorMessage = "Expected array as value for \"provides\".";
+        ErrorMessage = "Expected object as value for \"provides\".";
         return false;
       }
     } else if (KeyValue == "requires") {
@@ -476,5 +485,23 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
     ErrorMessage = "Missing key in translation-unit: \"arguments\".";
     return false;
   }
+  SmallString<8> FileStorage;
+  StringRef FileName = Source->getValue(FileStorage);
+  SmallString<128> NativeFilePath;
+  if (llvm::sys::path::is_relative(FileName)) {
+    SmallString<8> DirectoryStorage;
+    SmallString<128> AbsolutePath(WorkDirectory->getValue(DirectoryStorage));
+    llvm::sys::path::append(AbsolutePath, FileName);
+    llvm::sys::path::native(AbsolutePath, NativeFilePath);
+  } else {
+    llvm::sys::path::native(FileName, NativeFilePath);
+  }
+  llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
+  auto Cmd = CompileCommandRef(WorkDirectory, Source, Command, Object);
+
+  IndexByFile[NativeFilePath].push_back(Cmd);
+  AllCommands.push_back(Cmd);
+  MatchTrie.insert(NativeFilePath);
+
   return true;
 }

>From 6fbed3bc11520b13f172deb068e7cd349234df90 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Thu, 21 May 2026 21:19:52 -0700
Subject: [PATCH 05/12] expose module functions from compile database (hack for
 now to get up and running

---
 .../clangd/GlobalCompilationDatabase.cpp      |  1 +
 clang-tools-extra/clangd/ProjectModules.h     |  2 +-
 .../clang/Tooling/CommonOptionsParser.h       | 12 ++++++----
 .../clang/Tooling/CompilationDatabase.h       | 23 +++++++++++++++++--
 .../include/clang/Tooling/JSONBuildDatabase.h |  4 ++++
 .../clang/Tooling/JSONCompilationDatabase.h   |  4 ++++
 clang/lib/Tooling/CommonOptionsParser.cpp     | 19 ++++++++++-----
 clang/lib/Tooling/CompilationDatabase.cpp     |  9 ++++++++
 ...ExpandResponseFilesCompilationDatabase.cpp |  8 +++++++
 .../GuessTargetAndModeCompilationDatabase.cpp |  8 +++++++
 .../InterpolatingCompilationDatabase.cpp      | 21 +++++++++++------
 clang/lib/Tooling/JSONBuildDatabase.cpp       | 16 +++++++++----
 clang/lib/Tooling/JSONCompilationDatabase.cpp | 10 ++++++++
 .../Tooling/LocateToolCompilationDatabase.cpp |  8 +++++++
 14 files changed, 120 insertions(+), 25 deletions(-)

diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 11205a1b7c646..522dc46764dc7 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -267,6 +267,7 @@ parseBuildDatabaseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
   }
   return nullptr;
 }
+// Adapt CDB-loading functions to a common interface for DirectoryCache::load().
 static std::unique_ptr<tooling::CompilationDatabase>
 parseComplilationCommandsJSON(PathRef Path, llvm::StringRef Data,
                               std::string &Error) {
diff --git a/clang-tools-extra/clangd/ProjectModules.h b/clang-tools-extra/clangd/ProjectModules.h
index fbf658bafe150..ee0136bfa51a7 100644
--- a/clang-tools-extra/clangd/ProjectModules.h
+++ b/clang-tools-extra/clangd/ProjectModules.h
@@ -60,7 +60,7 @@ class ProjectModules {
   virtual ~ProjectModules() = default;
 };
 
-/// Providing modules information for the project by scanning every file.
+/// Providing modules information for the project
 std::unique_ptr<ProjectModules> getProjectModules(
     std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
     const ThreadsafeFS &TFS);
diff --git a/clang/include/clang/Tooling/CommonOptionsParser.h b/clang/include/clang/Tooling/CommonOptionsParser.h
index 09310fd9d2d4e..0a785858d3a35 100644
--- a/clang/include/clang/Tooling/CommonOptionsParser.h
+++ b/clang/include/clang/Tooling/CommonOptionsParser.h
@@ -92,9 +92,7 @@ class CommonOptionsParser {
          const char *Overview = nullptr);
 
   /// Returns a reference to the loaded compilations database.
-  CompilationDatabase &getCompilations() {
-    return *Compilations;
-  }
+  CompilationDatabase &getCompilations() { return *Compilations; }
 
   /// Returns a list of source file paths to process.
   const std::vector<std::string> &getSourcePathList() const {
@@ -135,6 +133,10 @@ class ArgumentsAdjustingCompilations : public CompilationDatabase {
 
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override;
+  std::optional<std::string> getModuleName(StringRef FilePath) const override;
+
 private:
   std::unique_ptr<CompilationDatabase> Compilations;
   std::vector<ArgumentsAdjuster> Adjusters;
@@ -143,7 +145,7 @@ class ArgumentsAdjustingCompilations : public CompilationDatabase {
   adjustCommands(std::vector<CompileCommand> Commands) const;
 };
 
-}  // namespace tooling
-}  // namespace clang
+} // namespace tooling
+} // namespace clang
 
 #endif // LLVM_CLANG_TOOLING_COMMONOPTIONSPARSER_H
diff --git a/clang/include/clang/Tooling/CompilationDatabase.h b/clang/include/clang/Tooling/CompilationDatabase.h
index 36fe0812ebe97..91f86dd15126a 100644
--- a/clang/include/clang/Tooling/CompilationDatabase.h
+++ b/clang/include/clang/Tooling/CompilationDatabase.h
@@ -126,8 +126,23 @@ class CompilationDatabase {
   /// $ clang++ -o production a.cc b.cc -DPRODUCTION
   /// A compilation database representing the project would return both command
   /// lines for a.cc and b.cc and only the first command line for t.cc.
-  virtual std::vector<CompileCommand> getCompileCommands(
-      StringRef FilePath) const = 0;
+  virtual std::vector<CompileCommand>
+  getCompileCommands(StringRef FilePath) const = 0;
+
+  // Returns all required modules for the specified file.
+  //
+  // This is the set of imported modules that are required to compile this file.
+  virtual std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const = 0;
+
+  // Returns the module name for the specified file.
+  //
+  // Will return no value when the module information is unknown (not provided)
+  // or unknowable (C). Empty string indicates this file does not produce a
+  // named module. Otherwise returns the name of the module exported by this
+  // file
+  virtual std::optional<std::string>
+  getModuleName(StringRef FilePath) const = 0;
 
   /// Returns the list of all files available in the compilation database.
   ///
@@ -207,6 +222,10 @@ class FixedCompilationDatabase : public CompilationDatabase {
   std::vector<CompileCommand>
   getCompileCommands(StringRef FilePath) const override;
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override;
+  std::optional<std::string> getModuleName(StringRef FilePath) const override;
+
 private:
   /// This is built up to contain a single entry vector to be returned from
   /// getCompileCommands after adding the positional argument.
diff --git a/clang/include/clang/Tooling/JSONBuildDatabase.h b/clang/include/clang/Tooling/JSONBuildDatabase.h
index 403aae91a19bd..4d8c4dc2f86e2 100644
--- a/clang/include/clang/Tooling/JSONBuildDatabase.h
+++ b/clang/include/clang/Tooling/JSONBuildDatabase.h
@@ -89,6 +89,10 @@ class JSONBuildDatabase : public CompilationDatabase {
   /// database.
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override;
+  std::optional<std::string> getModuleName(StringRef FilePath) const override;
+
 private:
   /// Constructs a JSON build database on a memory buffer.
   JSONBuildDatabase(std::unique_ptr<llvm::MemoryBuffer> Database)
diff --git a/clang/include/clang/Tooling/JSONCompilationDatabase.h b/clang/include/clang/Tooling/JSONCompilationDatabase.h
index 96582457c63d5..1762a5e523ef1 100644
--- a/clang/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/clang/include/clang/Tooling/JSONCompilationDatabase.h
@@ -92,6 +92,10 @@ class JSONCompilationDatabase : public CompilationDatabase {
   /// database.
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override;
+  std::optional<std::string> getModuleName(StringRef FilePath) const override;
+
 private:
   /// Constructs a JSON compilation database on a memory buffer.
   JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database,
diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp
index c8c3ca98323e2..f51047cb8f4b7 100644
--- a/clang/lib/Tooling/CommonOptionsParser.cpp
+++ b/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -57,13 +57,12 @@ void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
   Adjusters.push_back(std::move(Adjuster));
 }
 
-std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
-    StringRef FilePath) const {
+std::vector<CompileCommand>
+ArgumentsAdjustingCompilations::getCompileCommands(StringRef FilePath) const {
   return adjustCommands(Compilations->getCompileCommands(FilePath));
 }
 
-std::vector<std::string>
-ArgumentsAdjustingCompilations::getAllFiles() const {
+std::vector<std::string> ArgumentsAdjustingCompilations::getAllFiles() const {
   return Compilations->getAllFiles();
 }
 
@@ -80,6 +79,15 @@ std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
   return Commands;
 }
 
+std::vector<std::string>
+ArgumentsAdjustingCompilations::getRequiredModules(StringRef FilePath) const {
+  return {};
+}
+std::optional<std::string>
+ArgumentsAdjustingCompilations::getModuleName(StringRef FilePath) const {
+  return std::nullopt;
+}
+
 llvm::Error CommonOptionsParser::init(
     int &argc, const char **argv, cl::OptionCategory &Category,
     llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
@@ -140,8 +148,7 @@ llvm::Error CommonOptionsParser::init(
     }
   }
   auto AdjustingCompilations =
-      std::make_unique<ArgumentsAdjustingCompilations>(
-          std::move(Compilations));
+      std::make_unique<ArgumentsAdjustingCompilations>(std::move(Compilations));
   Adjuster =
       getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
   Adjuster = combineAdjusters(
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index 187e1223f5cef..1b92c238f3d64 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -382,6 +382,15 @@ FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
   return Result;
 }
 
+std::vector<std::string>
+FixedCompilationDatabase::getRequiredModules(StringRef FilePath) const {
+  return {};
+}
+std::optional<std::string>
+FixedCompilationDatabase::getModuleName(StringRef FilePath) const {
+  return std::nullopt;
+}
+
 namespace {
 
 class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
index 22d0057a28f81..360c1ba8b9f06 100644
--- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -43,6 +43,14 @@ class ExpandResponseFilesDatabase : public CompilationDatabase {
     return expand(Base->getAllCompileCommands());
   }
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override {
+    return {};
+  }
+  std::optional<std::string> getModuleName(StringRef FilePath) const override {
+    return std::nullopt;
+  }
+
 private:
   std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const {
     for (auto &Cmd : Cmds)
diff --git a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
index b6c1c0952aca9..eeb73f9e1bc45 100644
--- a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
+++ b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
@@ -34,6 +34,14 @@ class TargetAndModeAdderDatabase : public CompilationDatabase {
     return addTargetAndMode(Base->getCompileCommands(FilePath));
   }
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override {
+    return {};
+  }
+  std::optional<std::string> getModuleName(StringRef FilePath) const override {
+    return std::nullopt;
+  }
+
 private:
   std::vector<CompileCommand>
   addTargetAndMode(std::vector<CompileCommand> Cmds) const {
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 08ee02f639a4f..b67421e4de4d1 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -201,10 +201,9 @@ struct TransferableCommand {
 
       // Strip input and output files.
       if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
-          (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
-                           Opt.matches(OPT__SLASH_Fe) ||
-                           Opt.matches(OPT__SLASH_Fi) ||
-                           Opt.matches(OPT__SLASH_Fo))))
+          (ClangCLMode &&
+           (Opt.matches(OPT__SLASH_Fa) || Opt.matches(OPT__SLASH_Fe) ||
+            Opt.matches(OPT__SLASH_Fi) || Opt.matches(OPT__SLASH_Fo))))
         continue;
 
       // ...including when the inputs are passed after --.
@@ -224,8 +223,8 @@ struct TransferableCommand {
         continue;
       }
 
-      Cmd.CommandLine.insert(Cmd.CommandLine.end(),
-                             OldArgs.data() + OldPos, OldArgs.data() + Pos);
+      Cmd.CommandLine.insert(Cmd.CommandLine.end(), OldArgs.data() + OldPos,
+                             OldArgs.data() + Pos);
     }
 
     // Make use of -std iff -x was missing.
@@ -544,7 +543,7 @@ class FileIndex {
   StringSaver Strings;
   // Indexes of candidates by certain substrings.
   // String is lowercase and sorted, index points into OriginalPaths.
-  std::vector<SubstringAndIndex> Paths;      // Full path.
+  std::vector<SubstringAndIndex> Paths; // Full path.
   // Lang types obtained by guessing on the corresponding path. I-th element is
   // a type for the I-th path.
   std::vector<types::ID> Types;
@@ -584,6 +583,14 @@ class InterpolatingCompilationDatabase : public CompilationDatabase {
     return Inner->getAllCompileCommands();
   }
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override {
+    return {};
+  }
+  std::optional<std::string> getModuleName(StringRef FilePath) const override {
+    return std::nullopt;
+  }
+
 private:
   std::unique_ptr<CompilationDatabase> Inner;
   FileIndex Index;
diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index 4c3e75610c989..2ad4313b99437 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -30,10 +30,8 @@
 #include <cassert>
 #include <memory>
 #include <optional>
-#include <signal.h>
 #include <string>
 #include <system_error>
-#include <thread>
 #include <unistd.h>
 #include <utility>
 #include <vector>
@@ -42,13 +40,13 @@ using namespace clang;
 using namespace tooling;
 
 namespace {
-// This plugin locates a nearby compile_command.json file, and also infers
+// This plugin locates a nearby build_database.json file, and also infers
 // compile commands for files not present in the database.
 class JSONBuildDatabasePlugin : public CompilationDatabasePlugin {
   std::unique_ptr<CompilationDatabase>
   loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
     SmallString<1024> JSONDatabasePath(Directory);
-    llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
+    llvm::sys::path::append(JSONDatabasePath, "build_database.json");
     auto Base = JSONBuildDatabase::loadFromFile(JSONDatabasePath, ErrorMessage);
     return Base ? inferTargetAndDriverMode(
                       inferMissingCompileCommands(expandResponseFiles(
@@ -135,6 +133,16 @@ std::vector<CompileCommand> JSONBuildDatabase::getAllCompileCommands() const {
   return Commands;
 }
 
+std::vector<std::string>
+JSONBuildDatabase::getRequiredModules(StringRef FilePath) const {
+  return {};
+}
+
+std::optional<std::string>
+JSONBuildDatabase::getModuleName(StringRef FilePath) const {
+  return "tset";
+}
+
 static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
   Name.consume_back(".exe");
   return Name;
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 9155b01f3fe13..adaf94a1e0e9c 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -261,6 +261,16 @@ JSONCompilationDatabase::getAllCompileCommands() const {
   return Commands;
 }
 
+std::vector<std::string>
+JSONCompilationDatabase::getRequiredModules(StringRef FilePath) const {
+  return {};
+}
+
+std::optional<std::string>
+JSONCompilationDatabase::getModuleName(StringRef FilePath) const {
+  return std::nullopt;
+}
+
 static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
   Name.consume_back(".exe");
   return Name;
diff --git a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
index 033f69f3760c6..34ced90c32379 100644
--- a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
+++ b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
@@ -36,6 +36,14 @@ class LocationAdderDatabase : public CompilationDatabase {
     return addLocation(Base->getCompileCommands(FilePath));
   }
 
+  std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const override {
+    return {};
+  }
+  std::optional<std::string> getModuleName(StringRef FilePath) const override {
+    return std::nullopt;
+  }
+
 private:
   std::vector<CompileCommand>
   addLocation(std::vector<CompileCommand> Cmds) const {

>From 4d577dc44565187086e5d9f29971660ceba450fa Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Fri, 22 May 2026 12:57:21 -0700
Subject: [PATCH 06/12] Finish building up set lookup and implement module
 manager interface

---
 clang-tools-extra/clangd/ProjectModules.cpp   | 109 ++++++++-
 .../clang/Tooling/CommonOptionsParser.h       |   4 -
 .../clang/Tooling/CompilationDatabase.h       |  55 +++--
 .../include/clang/Tooling/JSONBuildDatabase.h |  62 +++--
 .../clang/Tooling/JSONCompilationDatabase.h   |   4 -
 clang/lib/Tooling/CommonOptionsParser.cpp     |   9 -
 clang/lib/Tooling/CompilationDatabase.cpp     |   9 -
 ...ExpandResponseFilesCompilationDatabase.cpp |   8 -
 .../GuessTargetAndModeCompilationDatabase.cpp |   8 -
 .../InterpolatingCompilationDatabase.cpp      |   8 -
 clang/lib/Tooling/JSONBuildDatabase.cpp       | 214 +++++++++++++++---
 clang/lib/Tooling/JSONCompilationDatabase.cpp |  10 -
 .../Tooling/LocateToolCompilationDatabase.cpp |   8 -
 13 files changed, 358 insertions(+), 150 deletions(-)

diff --git a/clang-tools-extra/clangd/ProjectModules.cpp b/clang-tools-extra/clangd/ProjectModules.cpp
index d3727171bff12..50f094be3c0cf 100644
--- a/clang-tools-extra/clangd/ProjectModules.cpp
+++ b/clang-tools-extra/clangd/ProjectModules.cpp
@@ -347,6 +347,80 @@ class ScanningAllProjectModules : public ProjectModules {
   CommandMangler Mangler;
 };
 
+/// Reads project module information directly from build database.
+///
+/// The build database contains the translation unit sets and their visibility
+/// into other sets. This heirarchy allows for a single project to contain
+/// multiple isolated linked programs that guarantee unique module names within
+/// the context of a set and all visible sets while allowing for duplicate
+/// module names within the larger project.
+///
+/// Note the build database can be stale, so results from this backend
+/// should be treated as preferred hints rather than unquestionable truth.
+/// The compound layer below validates or falls back when needed.
+class BuildDatabaseProjectModules : public ProjectModules {
+public:
+  BuildDatabaseProjectModules(
+      std::shared_ptr<const clang::tooling::CompilationDatabase> CDB)
+      : CDB(std::move(CDB)) {}
+
+  std::vector<std::string> getRequiredModules(PathRef File) override {
+    const auto *ModuleManager = CDB->getModuleManager();
+    if (ModuleManager)
+      return ModuleManager->getRequiredModules(File);
+
+    return {};
+  }
+
+  std::string getModuleNameForSource(PathRef File) override {
+    const auto *ModuleManager = CDB->getModuleManager();
+    if (ModuleManager) {
+      auto ModuleName = ModuleManager->getModuleName(File);
+      if (ModuleName)
+        return *ModuleName;
+    }
+
+    return "";
+  }
+
+  ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override {
+    const auto *ModuleManager = CDB->getModuleManager();
+    if (ModuleManager)
+      return (ModuleNameState)ModuleManager->getModuleNameState(ModuleName);
+
+    return ModuleNameState::Unknown;
+  }
+
+  std::string getSourceForModuleName(llvm::StringRef ModuleName,
+                                     PathRef RequiredSourceFile) override {
+    const auto *ModuleManager = CDB->getModuleManager();
+    if (ModuleManager)
+      return ModuleManager->getSourceForModuleName(ModuleName,
+                                                   RequiredSourceFile);
+
+    return "";
+  }
+
+  void setCommandMangler(CommandMangler Mangler) override {
+    this->Mangler = std::move(Mangler);
+  }
+
+private:
+  std::shared_ptr<const clang::tooling::CompilationDatabase> CDB;
+  CommandMangler Mangler;
+
+  llvm::StringMap<std::string> PCMToSource;
+
+  using DistinctSourceSet = llvm::StringSet<>;
+  llvm::StringMap<DistinctSourceSet> ModuleNameToDistinctSources;
+
+  struct RecoveredModuleName {
+    std::string Name;
+    bool Ambiguous = false;
+  };
+  llvm::StringMap<RecoveredModuleName> SourceToModuleName;
+};
+
 /// Reads project module information directly from compile commands.
 ///
 /// The key observation is that compile commands may already encode the mapping
@@ -528,7 +602,8 @@ class CompoundProjectModules : public ProjectModules {
   CompoundProjectModules(
       std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
       const ThreadsafeFS &TFS)
-      : CompileCommands(
+      : BuildDatabase(std::make_unique<BuildDatabaseProjectModules>(CDB)),
+        CompileCommands(
             std::make_unique<CompileCommandsProjectModules>(CDB, TFS)),
         Scanning(
             std::make_unique<ScanningAllProjectModules>(std::move(CDB), TFS)) {}
@@ -545,20 +620,33 @@ class CompoundProjectModules : public ProjectModules {
 
   std::string getSourceForModuleName(llvm::StringRef ModuleName,
                                      PathRef RequiredSourceFile) override {
-    auto FromCompileCommands =
-        CompileCommands->getSourceForModuleName(ModuleName, RequiredSourceFile);
-    // Check if the source still declares the module.
-    // This is to validate compile-command-derived results may be stale and
-    // scan a single file is fast enough. We just don't want to scan the project
-    // entirely.
-    if (!FromCompileCommands.empty() &&
-        Scanning->getModuleNameForSource(FromCompileCommands) == ModuleName)
-      return FromCompileCommands;
+    auto FromBuildDatabase =
+        BuildDatabase->getSourceForModuleName(ModuleName, RequiredSourceFile);
+    if (!FromBuildDatabase.empty()) {
+      // Check if the source still declares the module.
+      // This is to validate compile-command-derived results may be stale and
+      // scan a single file is fast enough. We just don't want to scan the
+      // project entirely.
+      if (Scanning->getModuleNameForSource(FromBuildDatabase) == ModuleName)
+        return FromBuildDatabase;
+    } else {
+      // The build database does not have module knowledge. Fall back to parse
+      // compile command.
+      auto FromCompileCommands = CompileCommands->getSourceForModuleName(
+          ModuleName, RequiredSourceFile);
+      if (!FromCompileCommands.empty() &&
+          Scanning->getModuleNameForSource(FromCompileCommands) == ModuleName)
+        return FromCompileCommands;
+    }
 
     return Scanning->getSourceForModuleName(ModuleName, RequiredSourceFile);
   }
 
   ModuleNameState getModuleNameState(llvm::StringRef ModuleName) override {
+    auto FromBuildDatabase = BuildDatabase->getModuleNameState(ModuleName);
+    if (FromBuildDatabase != ModuleNameState::Unknown)
+      return FromBuildDatabase;
+
     auto FromCompileCommands = CompileCommands->getModuleNameState(ModuleName);
     if (FromCompileCommands != ModuleNameState::Unknown)
       return FromCompileCommands;
@@ -577,6 +665,7 @@ class CompoundProjectModules : public ProjectModules {
   }
 
 private:
+  std::unique_ptr<BuildDatabaseProjectModules> BuildDatabase;
   std::unique_ptr<CompileCommandsProjectModules> CompileCommands;
   std::unique_ptr<ScanningAllProjectModules> Scanning;
   CommandMangler Mangler;
diff --git a/clang/include/clang/Tooling/CommonOptionsParser.h b/clang/include/clang/Tooling/CommonOptionsParser.h
index 0a785858d3a35..98deaf174fb53 100644
--- a/clang/include/clang/Tooling/CommonOptionsParser.h
+++ b/clang/include/clang/Tooling/CommonOptionsParser.h
@@ -133,10 +133,6 @@ class ArgumentsAdjustingCompilations : public CompilationDatabase {
 
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override;
-  std::optional<std::string> getModuleName(StringRef FilePath) const override;
-
 private:
   std::unique_ptr<CompilationDatabase> Compilations;
   std::vector<ArgumentsAdjuster> Adjusters;
diff --git a/clang/include/clang/Tooling/CompilationDatabase.h b/clang/include/clang/Tooling/CompilationDatabase.h
index 91f86dd15126a..c0d35a07ee94e 100644
--- a/clang/include/clang/Tooling/CompilationDatabase.h
+++ b/clang/include/clang/Tooling/CompilationDatabase.h
@@ -76,6 +76,36 @@ struct CompileCommand {
   }
 };
 
+class ModuleManager {
+public:
+  enum class ModuleNameState {
+    Unknown,
+    Unique,
+    Multiple,
+  };
+
+  // Returns all required modules for the specified file.
+  //
+  // This is the set of imported modules that are required to compile this file.
+  virtual std::vector<std::string>
+  getRequiredModules(StringRef FilePath) const = 0;
+
+  // Returns the module name for the specified file.
+  //
+  // Will return no value when the module information is unknown (not provided)
+  // or unknowable (C). Empty string indicates this file does not produce a
+  // named module. Otherwise returns the name of the module exported by this
+  // file
+  virtual std::optional<std::string>
+  getModuleName(StringRef FilePath) const = 0;
+
+  virtual ModuleNameState getModuleNameState(StringRef ModuleName) const = 0;
+
+  virtual std::string
+  getSourceForModuleName(StringRef ModuleName,
+                         StringRef RequiredSourceFile) const = 0;
+};
+
 /// Interface for compilation databases.
 ///
 /// A compilation database allows the user to retrieve compile command lines
@@ -129,21 +159,6 @@ class CompilationDatabase {
   virtual std::vector<CompileCommand>
   getCompileCommands(StringRef FilePath) const = 0;
 
-  // Returns all required modules for the specified file.
-  //
-  // This is the set of imported modules that are required to compile this file.
-  virtual std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const = 0;
-
-  // Returns the module name for the specified file.
-  //
-  // Will return no value when the module information is unknown (not provided)
-  // or unknowable (C). Empty string indicates this file does not produce a
-  // named module. Otherwise returns the name of the module exported by this
-  // file
-  virtual std::optional<std::string>
-  getModuleName(StringRef FilePath) const = 0;
-
   /// Returns the list of all files available in the compilation database.
   ///
   /// By default, returns nothing. Implementations should override this if they
@@ -160,6 +175,12 @@ class CompilationDatabase {
   /// By default, this is implemented in terms of getAllFiles() and
   /// getCompileCommands(). Subclasses may override this for efficiency.
   virtual std::vector<CompileCommand> getAllCompileCommands() const;
+
+  /// Returns the module manager.
+  ///
+  /// By default, returns nothing. Implementations should override this if they
+  /// can enumerate their source files.
+  virtual const ModuleManager *getModuleManager() const { return nullptr; }
 };
 
 /// A compilation database that returns a single compile command line.
@@ -222,10 +243,6 @@ class FixedCompilationDatabase : public CompilationDatabase {
   std::vector<CompileCommand>
   getCompileCommands(StringRef FilePath) const override;
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override;
-  std::optional<std::string> getModuleName(StringRef FilePath) const override;
-
 private:
   /// This is built up to contain a single entry vector to be returned from
   /// getCompileCommands after adding the positional argument.
diff --git a/clang/include/clang/Tooling/JSONBuildDatabase.h b/clang/include/clang/Tooling/JSONBuildDatabase.h
index 4d8c4dc2f86e2..38c401e05ad66 100644
--- a/clang/include/clang/Tooling/JSONBuildDatabase.h
+++ b/clang/include/clang/Tooling/JSONBuildDatabase.h
@@ -20,6 +20,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/YAMLParser.h"
@@ -57,7 +58,7 @@ namespace tooling {
 ///
 /// JSON build databases can for example be generated in CMake projects
 /// by setting the flag -DCMAKE_EXPORT_BUILD_DATABASE.
-class JSONBuildDatabase : public CompilationDatabase {
+class JSONBuildDatabase : public CompilationDatabase, ModuleManager {
 public:
   /// Loads a JSON build database from the specified file.
   ///
@@ -89,16 +90,43 @@ class JSONBuildDatabase : public CompilationDatabase {
   /// database.
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  const ModuleManager *getModuleManager() const override;
+
   std::vector<std::string>
   getRequiredModules(StringRef FilePath) const override;
   std::optional<std::string> getModuleName(StringRef FilePath) const override;
 
+  ModuleNameState getModuleNameState(StringRef ModuleName) const override;
+
+  std::string
+  getSourceForModuleName(StringRef ModuleName,
+                         StringRef RequiredSourceFile) const override;
+
 private:
   /// Constructs a JSON build database on a memory buffer.
   JSONBuildDatabase(std::unique_ptr<llvm::MemoryBuffer> Database)
       : Database(std::move(Database)),
         YAMLStream(this->Database->getBuffer(), SM) {}
 
+  // Container for a compile command references where 'commandline'
+  // points to the corresponding scalar nodes in the YAML stream.
+  // The output field may be a nullptr.
+  struct TranslationUnitRef {
+    llvm::yaml::ScalarNode *SetName;
+    llvm::yaml::ScalarNode *Directory;
+    llvm::yaml::ScalarNode *Filename;
+    std::vector<llvm::yaml::ScalarNode *> CommandLine;
+    llvm::yaml::ScalarNode *Output;
+    llvm::yaml::ScalarNode *ProvidesModuleName;
+    llvm::yaml::ScalarNode *ProvidesModulePCM;
+    std::vector<llvm::yaml::ScalarNode *> RequiredModules;
+  };
+
+  struct TranslationUnitSet {
+    std::vector<llvm::yaml::ScalarNode *> VisibleSets;
+    std::vector<TranslationUnitRef> TranslationUnits;
+  };
+
   /// Parses the database file and creates the index.
   ///
   /// Returns whether parsing succeeded. Sets ErrorMessage if parsing
@@ -106,30 +134,28 @@ class JSONBuildDatabase : public CompilationDatabase {
   bool parse(std::string &ErrorMessage);
   bool parseRoot(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
   bool parseSet(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
-  bool parseTU(std::string &ErrorMessage, llvm::yaml::MappingNode *Object);
+  bool parseTU(std::string &ErrorMessage, llvm::yaml::MappingNode *Object,
+               TranslationUnitRef &TURef);
 
-  // Tuple (directory, filename, commandline, output) where 'commandline'
-  // points to the corresponding scalar nodes in the YAML stream.
-  // If the command line contains a single argument, it is a shell-escaped
-  // command line.
-  // Otherwise, each entry in the command line vector is a literal
-  // argument to the compiler.
-  // The output field may be a nullptr.
-  using CompileCommandRef =
-      std::tuple<llvm::yaml::ScalarNode *, llvm::yaml::ScalarNode *,
-                 std::vector<llvm::yaml::ScalarNode *>,
-                 llvm::yaml::ScalarNode *>;
+  const TranslationUnitRef *getTUForSource(StringRef FilePath) const;
+  const TranslationUnitRef *getTUForModule(StringRef ModuleName,
+                                           StringRef SetName) const;
 
-  /// Converts the given array of CompileCommandRefs to CompileCommands.
-  void getCommands(ArrayRef<CompileCommandRef> CommandsRef,
+  /// Converts the given array of TranslationUnitRefs to CompileCommands.
+  void getCommands(ArrayRef<TranslationUnitRef> CommandsRef,
                    std::vector<CompileCommand> &Commands) const;
 
-  // Maps file paths to the compile command lines for that file.
-  llvm::StringMap<std::vector<CompileCommandRef>> IndexByFile;
+  // Maps file paths to the translation units for that file.
+  llvm::StringMap<std::vector<TranslationUnitRef>> IndexByFile;
+  llvm::StringMap<TranslationUnitSet> IndexBySet;
 
   /// All the compile commands in the order that they were provided in the
   /// JSON stream.
-  std::vector<CompileCommandRef> AllCommands;
+  std::vector<TranslationUnitRef> AllCommands;
+
+  // Module name state lookup to track unique names
+  using DistinctSourceSet = llvm::StringSet<>;
+  llvm::StringMap<DistinctSourceSet> ModuleNameToDistinctSources;
 
   FileMatchTrie MatchTrie;
 
diff --git a/clang/include/clang/Tooling/JSONCompilationDatabase.h b/clang/include/clang/Tooling/JSONCompilationDatabase.h
index 1762a5e523ef1..96582457c63d5 100644
--- a/clang/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/clang/include/clang/Tooling/JSONCompilationDatabase.h
@@ -92,10 +92,6 @@ class JSONCompilationDatabase : public CompilationDatabase {
   /// database.
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override;
-  std::optional<std::string> getModuleName(StringRef FilePath) const override;
-
 private:
   /// Constructs a JSON compilation database on a memory buffer.
   JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database,
diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp
index f51047cb8f4b7..980b38bc0f4d6 100644
--- a/clang/lib/Tooling/CommonOptionsParser.cpp
+++ b/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -79,15 +79,6 @@ std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
   return Commands;
 }
 
-std::vector<std::string>
-ArgumentsAdjustingCompilations::getRequiredModules(StringRef FilePath) const {
-  return {};
-}
-std::optional<std::string>
-ArgumentsAdjustingCompilations::getModuleName(StringRef FilePath) const {
-  return std::nullopt;
-}
-
 llvm::Error CommonOptionsParser::init(
     int &argc, const char **argv, cl::OptionCategory &Category,
     llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index 1b92c238f3d64..187e1223f5cef 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -382,15 +382,6 @@ FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
   return Result;
 }
 
-std::vector<std::string>
-FixedCompilationDatabase::getRequiredModules(StringRef FilePath) const {
-  return {};
-}
-std::optional<std::string>
-FixedCompilationDatabase::getModuleName(StringRef FilePath) const {
-  return std::nullopt;
-}
-
 namespace {
 
 class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
index 360c1ba8b9f06..22d0057a28f81 100644
--- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -43,14 +43,6 @@ class ExpandResponseFilesDatabase : public CompilationDatabase {
     return expand(Base->getAllCompileCommands());
   }
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override {
-    return {};
-  }
-  std::optional<std::string> getModuleName(StringRef FilePath) const override {
-    return std::nullopt;
-  }
-
 private:
   std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const {
     for (auto &Cmd : Cmds)
diff --git a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
index eeb73f9e1bc45..b6c1c0952aca9 100644
--- a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
+++ b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
@@ -34,14 +34,6 @@ class TargetAndModeAdderDatabase : public CompilationDatabase {
     return addTargetAndMode(Base->getCompileCommands(FilePath));
   }
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override {
-    return {};
-  }
-  std::optional<std::string> getModuleName(StringRef FilePath) const override {
-    return std::nullopt;
-  }
-
 private:
   std::vector<CompileCommand>
   addTargetAndMode(std::vector<CompileCommand> Cmds) const {
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index b67421e4de4d1..93b1a6eab9e28 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -583,14 +583,6 @@ class InterpolatingCompilationDatabase : public CompilationDatabase {
     return Inner->getAllCompileCommands();
   }
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override {
-    return {};
-  }
-  std::optional<std::string> getModuleName(StringRef FilePath) const override {
-    return std::nullopt;
-  }
-
 private:
   std::unique_ptr<CompilationDatabase> Inner;
   FileIndex Index;
diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index 2ad4313b99437..4dd54ad891556 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -112,11 +112,11 @@ JSONBuildDatabase::getCompileCommands(StringRef FilePath) const {
   StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
   if (Match.empty())
     return {};
-  const auto CommandsRefI = IndexByFile.find(Match);
-  if (CommandsRefI == IndexByFile.end())
+  const auto TURefI = IndexByFile.find(Match);
+  if (TURefI == IndexByFile.end())
     return {};
   std::vector<CompileCommand> Commands;
-  getCommands(CommandsRefI->getValue(), Commands);
+  getCommands(TURefI->getValue(), Commands);
   return Commands;
 }
 
@@ -133,14 +133,107 @@ std::vector<CompileCommand> JSONBuildDatabase::getAllCompileCommands() const {
   return Commands;
 }
 
+const ModuleManager *JSONBuildDatabase::getModuleManager() const {
+  return this;
+}
+
 std::vector<std::string>
 JSONBuildDatabase::getRequiredModules(StringRef FilePath) const {
-  return {};
+
+  const auto *TURef = getTUForSource(FilePath);
+  std::vector<std::string> RequiredModules;
+  if (TURef) {
+    for (const auto &RequiredModule : TURef->RequiredModules) {
+      SmallString<8> RequiredModuleStorage;
+      RequiredModules.emplace_back(
+          RequiredModule->getValue(RequiredModuleStorage));
+    }
+  }
+  return RequiredModules;
 }
 
 std::optional<std::string>
 JSONBuildDatabase::getModuleName(StringRef FilePath) const {
-  return "tset";
+  const auto *TURef = getTUForSource(FilePath);
+  if (TURef && TURef->ProvidesModuleName) {
+    SmallString<8> ModuleNameStorage;
+    return TURef->ProvidesModuleName->getValue(ModuleNameStorage).str();
+  }
+  return std::nullopt;
+}
+
+ModuleManager::ModuleNameState
+JSONBuildDatabase::getModuleNameState(StringRef ModuleName) const {
+  auto It = ModuleNameToDistinctSources.find(ModuleName);
+  if (It == ModuleNameToDistinctSources.end())
+    return ModuleNameState::Unknown;
+  return It->second.size() > 1 ? ModuleNameState::Multiple
+                               : ModuleNameState::Unique;
+}
+
+std::string
+JSONBuildDatabase::getSourceForModuleName(StringRef ModuleName,
+                                          StringRef RequiredSourceFile) const {
+
+  const auto *RequiredSourceTURef = getTUForSource(RequiredSourceFile);
+  if (RequiredSourceTURef) {
+    SmallString<8> SetNameStorage;
+    SmallString<8> FilenameStorage;
+    auto SetName = RequiredSourceTURef->SetName->getValue(SetNameStorage);
+    // First attempt to find the matching module in the current set
+    const auto *ModuleTURef = getTUForModule(ModuleName, SetName);
+    if (ModuleTURef)
+      return ModuleTURef->Filename->getValue(FilenameStorage).str();
+    // Could not find in current set, check all visible sets
+    const auto TUSetI = IndexBySet.find(SetName);
+    if (TUSetI == IndexBySet.end())
+      return {};
+    for (const auto &VisibleSet : TUSetI->getValue().VisibleSets) {
+      ModuleTURef =
+          getTUForModule(ModuleName, VisibleSet->getValue(SetNameStorage));
+      if (ModuleTURef)
+        return ModuleTURef->Filename->getValue(FilenameStorage).str();
+    }
+  }
+  return {};
+}
+
+const JSONBuildDatabase::TranslationUnitRef *
+JSONBuildDatabase::getTUForSource(StringRef FilePath) const {
+  SmallString<128> NativeFilePath;
+  llvm::sys::path::native(FilePath, NativeFilePath);
+
+  std::string Error;
+  llvm::raw_string_ostream ES(Error);
+  StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
+  if (Match.empty())
+    return {};
+  const auto TURefI = IndexByFile.find(Match);
+  if (TURefI == IndexByFile.end())
+    return {};
+  // Return the first reference in the build database
+  // Not ideal, but without context this is the best we can do
+  for (const auto &TURef : TURefI->getValue()) {
+    return &TURef;
+  }
+  return nullptr;
+}
+
+const JSONBuildDatabase::TranslationUnitRef *
+JSONBuildDatabase::getTUForModule(StringRef ModuleName,
+                                  StringRef SetName) const {
+  const auto TUSetI = IndexBySet.find(SetName);
+  if (TUSetI == IndexBySet.end())
+    return {};
+  // Return the first reference in the build database
+  // Not ideal, but without context this is the best we can do
+  for (const auto &TURef : TUSetI->getValue().TranslationUnits) {
+
+    SmallString<8> ModuleNameStorage;
+    if (TURef.ProvidesModuleName->getValue(ModuleNameStorage) == ModuleName)
+      return &TURef;
+  }
+  return nullptr;
 }
 
 static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
@@ -167,8 +260,9 @@ static bool unwrapCommand(std::vector<std::string> &Args) {
     //                     We don't even notice this case, and all is well.
     //
     // We need to distinguish between the first and second case.
-    // The wrappers themselves don't take flags, so Args[1] is a compiler flag,
-    // an input file, or a compiler. Inputs have extensions, compilers don't.
+    // The wrappers themselves don't take flags, so Args[1] is a compiler
+    // flag, an input file, or a compiler. Inputs have extensions, compilers
+    // don't.
     bool HasCompiler =
         (Args[1][0] != '-') &&
         !llvm::sys::path::has_extension(stripExecutableExtension(Args[1]));
@@ -187,24 +281,25 @@ nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
   std::vector<std::string> Arguments;
   for (const auto *Node : Nodes)
     Arguments.push_back(std::string(Node->getValue(Storage)));
-  // There may be multiple wrappers: using distcc and ccache together is common.
+  // There may be multiple wrappers: using distcc and ccache together is
+  // common.
   while (unwrapCommand(Arguments))
     ;
   return Arguments;
 }
 
 void JSONBuildDatabase::getCommands(
-    ArrayRef<CompileCommandRef> CommandsRef,
+    ArrayRef<TranslationUnitRef> TUsRef,
     std::vector<CompileCommand> &Commands) const {
-  for (const auto &CommandRef : CommandsRef) {
+  for (const auto &TURef : TUsRef) {
     SmallString<8> DirectoryStorage;
     SmallString<32> FilenameStorage;
     SmallString<32> OutputStorage;
-    auto Output = std::get<3>(CommandRef);
-    Commands.emplace_back(std::get<0>(CommandRef)->getValue(DirectoryStorage),
-                          std::get<1>(CommandRef)->getValue(FilenameStorage),
-                          nodeToCommandLine(std::get<2>(CommandRef)),
-                          Output ? Output->getValue(OutputStorage) : "");
+    Commands.emplace_back(TURef.Directory->getValue(DirectoryStorage),
+                          TURef.Filename->getValue(FilenameStorage),
+                          nodeToCommandLine(TURef.CommandLine),
+                          TURef.Output ? TURef.Output->getValue(OutputStorage)
+                                       : "");
   }
 }
 
@@ -305,6 +400,7 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
   llvm::yaml::ScalarNode *Name = nullptr;
   llvm::yaml::SequenceNode *VisibleSets = nullptr;
   llvm::yaml::SequenceNode *TUs = nullptr;
+  std::vector<TranslationUnitRef> TURefs = {};
   for (auto &NextKeyValue : *SetObject) {
     auto *KeyString =
         dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -355,9 +451,11 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
           ErrorMessage = "Expected translation-units item as object.";
           return false;
         }
-        if (!parseTU(ErrorMessage, TUObject)) {
+        TranslationUnitRef TURef = {};
+        if (!parseTU(ErrorMessage, TUObject, TURef)) {
           return false;
         }
+        TURefs.push_back(std::move(TURef));
       }
     } else {
       ErrorMessage =
@@ -382,11 +480,34 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
     ErrorMessage = "Missing key in set: \"translation-units\".";
     return false;
   }
+  // Finalize the translation unit refs now that we have all the set info
+  for (auto &TURef : TURefs) {
+    // Attach the parent set name for easy lookups
+    TURef.SetName = Name;
+    // Build up the native file path
+    SmallString<8> FileStorage;
+    StringRef FileName = TURef.Filename->getValue(FileStorage);
+    SmallString<128> NativeFilePath;
+    if (llvm::sys::path::is_relative(FileName)) {
+      SmallString<8> DirectoryStorage;
+      SmallString<128> AbsolutePath(
+          TURef.Directory->getValue(DirectoryStorage));
+      llvm::sys::path::append(AbsolutePath, FileName);
+      llvm::sys::path::native(AbsolutePath, NativeFilePath);
+    } else {
+      llvm::sys::path::native(FileName, NativeFilePath);
+    }
+    llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
+    IndexByFile[NativeFilePath].push_back(TURef);
+    AllCommands.push_back(TURef);
+    MatchTrie.insert(NativeFilePath);
+  }
   return true;
 }
 
 bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
-                                llvm::yaml::MappingNode *TUObject) {
+                                llvm::yaml::MappingNode *TUObject,
+                                TranslationUnitRef &TURef) {
   llvm::yaml::SequenceNode *Arguments = nullptr;
   std::vector<llvm::yaml::ScalarNode *> Command;
   llvm::yaml::ScalarNode *Language = nullptr;
@@ -396,7 +517,10 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
   llvm::yaml::ScalarNode *Source = nullptr;
   llvm::yaml::ScalarNode *Object = nullptr;
   llvm::yaml::MappingNode *Provides = nullptr;
+  llvm::yaml::ScalarNode *ProvidesModuleName = nullptr;
+  llvm::yaml::ScalarNode *ProvidesModulePCM = nullptr;
   llvm::yaml::SequenceNode *Requires = nullptr;
+  std::vector<llvm::yaml::ScalarNode *> RequiredModules;
   for (auto &NextKeyValue : *TUObject) {
     auto *KeyString =
         dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@@ -467,12 +591,43 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
         ErrorMessage = "Expected object as value for \"provides\".";
         return false;
       }
+      for (auto &NextProvidesKeyValue : *Provides) {
+        // The spec allows multiple of module provide, but C++ only allows one
+        if (ProvidesModuleName) {
+          ErrorMessage = "TU can only provide one module.";
+          return false;
+        }
+
+        auto *ProvidesKeyString = dyn_cast_if_present<llvm::yaml::ScalarNode>(
+            NextProvidesKeyValue.getKey());
+        if (!ProvidesKeyString) {
+          ErrorMessage = "Expected strings as key.";
+          return false;
+        }
+        auto *ProvidesValue = dyn_cast_if_present<llvm::yaml::ScalarNode>(
+            NextProvidesKeyValue.getValue());
+        if (!ProvidesValue) {
+          ErrorMessage = "Expected string as provides value.";
+          return false;
+        }
+
+        ProvidesModuleName = ProvidesKeyString;
+        ProvidesModulePCM = ProvidesValue;
+      }
     } else if (KeyValue == "requires") {
       Requires = dyn_cast<llvm::yaml::SequenceNode>(Value);
       if (!Requires) {
         ErrorMessage = "Expected array as value for \"requires\".";
         return false;
       }
+      for (auto &RequiredModule : *Requires) {
+        auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&RequiredModule);
+        if (!Scalar) {
+          ErrorMessage = "Only strings are allowed in 'requires'.";
+          return false;
+        }
+        RequiredModules.push_back(Scalar);
+      }
     } else {
       ErrorMessage = ("Unknown key in translation-unit: \"" +
                       KeyString->getRawValue() + "\"")
@@ -493,23 +648,12 @@ bool JSONBuildDatabase::parseTU(std::string &ErrorMessage,
     ErrorMessage = "Missing key in translation-unit: \"arguments\".";
     return false;
   }
-  SmallString<8> FileStorage;
-  StringRef FileName = Source->getValue(FileStorage);
-  SmallString<128> NativeFilePath;
-  if (llvm::sys::path::is_relative(FileName)) {
-    SmallString<8> DirectoryStorage;
-    SmallString<128> AbsolutePath(WorkDirectory->getValue(DirectoryStorage));
-    llvm::sys::path::append(AbsolutePath, FileName);
-    llvm::sys::path::native(AbsolutePath, NativeFilePath);
-  } else {
-    llvm::sys::path::native(FileName, NativeFilePath);
-  }
-  llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
-  auto Cmd = CompileCommandRef(WorkDirectory, Source, Command, Object);
-
-  IndexByFile[NativeFilePath].push_back(Cmd);
-  AllCommands.push_back(Cmd);
-  MatchTrie.insert(NativeFilePath);
-
+  TURef.Directory = WorkDirectory;
+  TURef.Filename = Source;
+  TURef.CommandLine = std::move(Command);
+  TURef.Output = Object;
+  TURef.ProvidesModuleName = ProvidesModuleName;
+  TURef.ProvidesModulePCM = ProvidesModulePCM;
+  TURef.RequiredModules = std::move(RequiredModules);
   return true;
 }
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index adaf94a1e0e9c..9155b01f3fe13 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -261,16 +261,6 @@ JSONCompilationDatabase::getAllCompileCommands() const {
   return Commands;
 }
 
-std::vector<std::string>
-JSONCompilationDatabase::getRequiredModules(StringRef FilePath) const {
-  return {};
-}
-
-std::optional<std::string>
-JSONCompilationDatabase::getModuleName(StringRef FilePath) const {
-  return std::nullopt;
-}
-
 static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
   Name.consume_back(".exe");
   return Name;
diff --git a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
index 34ced90c32379..033f69f3760c6 100644
--- a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
+++ b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
@@ -36,14 +36,6 @@ class LocationAdderDatabase : public CompilationDatabase {
     return addLocation(Base->getCompileCommands(FilePath));
   }
 
-  std::vector<std::string>
-  getRequiredModules(StringRef FilePath) const override {
-    return {};
-  }
-  std::optional<std::string> getModuleName(StringRef FilePath) const override {
-    return std::nullopt;
-  }
-
 private:
   std::vector<CompileCommand>
   addLocation(std::vector<CompileCommand> Cmds) const {

>From d4656c91e9a1b29242df23b2514fe561b6438ca4 Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Fri, 22 May 2026 15:28:18 -0700
Subject: [PATCH 07/12] Build set index and pass through module manager

---
 .../clang/Tooling/CommonOptionsParser.h       |  2 ++
 .../clang/Tooling/CompilationDatabase.h       |  4 ++-
 .../clang/Tooling/JSONCompilationDatabase.h   |  2 ++
 ...ExpandResponseFilesCompilationDatabase.cpp |  4 +++
 .../GuessTargetAndModeCompilationDatabase.cpp |  2 ++
 .../InterpolatingCompilationDatabase.cpp      |  4 +++
 clang/lib/Tooling/JSONBuildDatabase.cpp       | 26 ++++++++++++++++---
 .../Tooling/LocateToolCompilationDatabase.cpp |  2 ++
 8 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Tooling/CommonOptionsParser.h b/clang/include/clang/Tooling/CommonOptionsParser.h
index 98deaf174fb53..1083fc046ea3f 100644
--- a/clang/include/clang/Tooling/CommonOptionsParser.h
+++ b/clang/include/clang/Tooling/CommonOptionsParser.h
@@ -133,6 +133,8 @@ class ArgumentsAdjustingCompilations : public CompilationDatabase {
 
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  const ModuleManager *getModuleManager() const override { return nullptr; }
+
 private:
   std::unique_ptr<CompilationDatabase> Compilations;
   std::vector<ArgumentsAdjuster> Adjusters;
diff --git a/clang/include/clang/Tooling/CompilationDatabase.h b/clang/include/clang/Tooling/CompilationDatabase.h
index c0d35a07ee94e..72739849d6ba2 100644
--- a/clang/include/clang/Tooling/CompilationDatabase.h
+++ b/clang/include/clang/Tooling/CompilationDatabase.h
@@ -180,7 +180,7 @@ class CompilationDatabase {
   ///
   /// By default, returns nothing. Implementations should override this if they
   /// can enumerate their source files.
-  virtual const ModuleManager *getModuleManager() const { return nullptr; }
+  virtual const ModuleManager *getModuleManager() const = 0;
 };
 
 /// A compilation database that returns a single compile command line.
@@ -243,6 +243,8 @@ class FixedCompilationDatabase : public CompilationDatabase {
   std::vector<CompileCommand>
   getCompileCommands(StringRef FilePath) const override;
 
+  const ModuleManager *getModuleManager() const override { return nullptr; }
+
 private:
   /// This is built up to contain a single entry vector to be returned from
   /// getCompileCommands after adding the positional argument.
diff --git a/clang/include/clang/Tooling/JSONCompilationDatabase.h b/clang/include/clang/Tooling/JSONCompilationDatabase.h
index 96582457c63d5..65e384b86f45d 100644
--- a/clang/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/clang/include/clang/Tooling/JSONCompilationDatabase.h
@@ -92,6 +92,8 @@ class JSONCompilationDatabase : public CompilationDatabase {
   /// database.
   std::vector<CompileCommand> getAllCompileCommands() const override;
 
+  const ModuleManager *getModuleManager() const override { return nullptr; }
+
 private:
   /// Constructs a JSON compilation database on a memory buffer.
   JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database,
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
index 22d0057a28f81..cfc6334107e5e 100644
--- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -43,6 +43,10 @@ class ExpandResponseFilesDatabase : public CompilationDatabase {
     return expand(Base->getAllCompileCommands());
   }
 
+  const ModuleManager *getModuleManager() const override {
+    return Base->getModuleManager();
+  }
+
 private:
   std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const {
     for (auto &Cmd : Cmds)
diff --git a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
index b6c1c0952aca9..2bfd88a7c3222 100644
--- a/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
+++ b/clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
@@ -34,6 +34,8 @@ class TargetAndModeAdderDatabase : public CompilationDatabase {
     return addTargetAndMode(Base->getCompileCommands(FilePath));
   }
 
+  const ModuleManager *getModuleManager() const override { return nullptr; }
+
 private:
   std::vector<CompileCommand>
   addTargetAndMode(std::vector<CompileCommand> Cmds) const {
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 93b1a6eab9e28..a7d59f22f6015 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -583,6 +583,10 @@ class InterpolatingCompilationDatabase : public CompilationDatabase {
     return Inner->getAllCompileCommands();
   }
 
+  const ModuleManager *getModuleManager() const override {
+    return Inner->getModuleManager();
+  }
+
 private:
   std::unique_ptr<CompilationDatabase> Inner;
   FileIndex Index;
diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index 4dd54ad891556..f3f4f613d0c9c 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -139,7 +139,6 @@ const ModuleManager *JSONBuildDatabase::getModuleManager() const {
 
 std::vector<std::string>
 JSONBuildDatabase::getRequiredModules(StringRef FilePath) const {
-
   const auto *TURef = getTUForSource(FilePath);
   std::vector<std::string> RequiredModules;
   if (TURef) {
@@ -174,7 +173,6 @@ JSONBuildDatabase::getModuleNameState(StringRef ModuleName) const {
 std::string
 JSONBuildDatabase::getSourceForModuleName(StringRef ModuleName,
                                           StringRef RequiredSourceFile) const {
-
   const auto *RequiredSourceTURef = getTUForSource(RequiredSourceFile);
   if (RequiredSourceTURef) {
     SmallString<8> SetNameStorage;
@@ -385,7 +383,8 @@ bool JSONBuildDatabase::parseRoot(std::string &ErrorMessage,
     return false;
   }
   // Check compatible version
-  if (Version->getRawValue() != "1") {
+  SmallString<10> VersionStorage;
+  if (Version->getValue(VersionStorage).str() != "1") {
     ErrorMessage =
         ("Unsupported version: \"" + Version->getRawValue() + "\"").str();
     return false;
@@ -399,6 +398,7 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
   llvm::yaml::ScalarNode *FamilyName = nullptr;
   llvm::yaml::ScalarNode *Name = nullptr;
   llvm::yaml::SequenceNode *VisibleSets = nullptr;
+  std::vector<llvm::yaml::ScalarNode *> VisibleSetsRefs = {};
   llvm::yaml::SequenceNode *TUs = nullptr;
   std::vector<TranslationUnitRef> TURefs = {};
   for (auto &NextKeyValue : *SetObject) {
@@ -439,6 +439,14 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
         ErrorMessage = "Expected array as value for \"visible-sets\".";
         return false;
       }
+      for (auto &VisibleSet : *VisibleSets) {
+        auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&VisibleSet);
+        if (!Scalar) {
+          ErrorMessage = "Only strings are allowed in 'visible-sets'.";
+          return false;
+        }
+        VisibleSetsRefs.push_back(Scalar);
+      }
     } else if (KeyValue == "translation-units") {
       TUs = dyn_cast<llvm::yaml::SequenceNode>(Value);
       if (!TUs) {
@@ -501,7 +509,19 @@ bool JSONBuildDatabase::parseSet(std::string &ErrorMessage,
     IndexByFile[NativeFilePath].push_back(TURef);
     AllCommands.push_back(TURef);
     MatchTrie.insert(NativeFilePath);
+    if (TURef.ProvidesModuleName) {
+      SmallString<8> ModuleNameStorage;
+      ModuleNameToDistinctSources
+          [TURef.ProvidesModuleName->getValue(ModuleNameStorage).str()]
+              .insert(NativeFilePath);
+    }
   }
+  // Generate lookup for each set
+  TranslationUnitSet TUSet = {};
+  TUSet.TranslationUnits = std::move(TURefs);
+  TUSet.VisibleSets = std::move(VisibleSetsRefs);
+  SmallString<8> NameStorage;
+  IndexBySet[Name->getValue(NameStorage)] = std::move(TUSet);
   return true;
 }
 
diff --git a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
index 033f69f3760c6..e14bf69d3c863 100644
--- a/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
+++ b/clang/lib/Tooling/LocateToolCompilationDatabase.cpp
@@ -36,6 +36,8 @@ class LocationAdderDatabase : public CompilationDatabase {
     return addLocation(Base->getCompileCommands(FilePath));
   }
 
+  const ModuleManager *getModuleManager() const override { return nullptr; }
+
 private:
   std::vector<CompileCommand>
   addLocation(std::vector<CompileCommand> Cmds) const {

>From e5409da6bb72282e1c3e85ac4808aa54c84f934a Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Fri, 22 May 2026 21:29:40 -0700
Subject: [PATCH 08/12] Fix seg fault

---
 clang/lib/Tooling/JSONBuildDatabase.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Tooling/JSONBuildDatabase.cpp b/clang/lib/Tooling/JSONBuildDatabase.cpp
index f3f4f613d0c9c..63b15f2849069 100644
--- a/clang/lib/Tooling/JSONBuildDatabase.cpp
+++ b/clang/lib/Tooling/JSONBuildDatabase.cpp
@@ -228,7 +228,8 @@ JSONBuildDatabase::getTUForModule(StringRef ModuleName,
   for (const auto &TURef : TUSetI->getValue().TranslationUnits) {
 
     SmallString<8> ModuleNameStorage;
-    if (TURef.ProvidesModuleName->getValue(ModuleNameStorage) == ModuleName)
+    if (TURef.ProvidesModuleName &&
+        TURef.ProvidesModuleName->getValue(ModuleNameStorage) == ModuleName)
       return &TURef;
   }
   return nullptr;

>From 77a7c156799e5ebf0416b6d3dc28dcc9ce16ae0f Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Sat, 23 May 2026 12:41:41 -0700
Subject: [PATCH 09/12] Stub out tests for now

---
 .../clangd/unittests/PrerequisiteModulesTest.cpp      | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
index b88213decea44..ad878c7d7f96e 100644
--- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
+++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp
@@ -142,6 +142,10 @@ class PerFileModulesCompilationDatabase : public GlobalCompilationDatabase {
 
     std::vector<std::string> getAllFiles() const override { return CDB.Files; }
 
+    tooling::ModuleManager *getModuleManager() const override {
+      return nullptr;
+    }
+
   private:
     const PerFileModulesCompilationDatabase &CDB;
   };
@@ -206,6 +210,10 @@ class MockDirectoryCompilationDatabase : public MockCompilationDatabase {
 
     void AddFile(StringRef File) { Files.push_back(File.str()); }
 
+    const tooling::ModuleManager *getModuleManager() const override {
+      return nullptr;
+    }
+
   private:
     MockDirectoryCompilationDatabase &MCDB;
     std::vector<std::string> Files;
@@ -574,7 +582,8 @@ int use() { return a; }
 
   ModulesBuilder Builder(CDB);
 
-  auto UseInfo = Builder.buildPrerequisiteModulesFor(getFullPath("Use.cpp"), FS);
+  auto UseInfo =
+      Builder.buildPrerequisiteModulesFor(getFullPath("Use.cpp"), FS);
   ASSERT_TRUE(UseInfo);
 
   HeaderSearchOptions HSOpts;

>From 3220694ec7e981b1c48338d9984f867240eac5eb Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Sat, 23 May 2026 15:11:36 -0700
Subject: [PATCH 10/12] Missing impl

---
 clang/tools/clang-scan-deps/ClangScanDeps.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 5322178a848e2..5bca122599f5b 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -850,6 +850,10 @@ getCompilationDatabase(int argc, char **argv, std::string &ErrorMessage) {
       return {Command};
     }
 
+    const tooling::ModuleManager *getModuleManager() const override {
+      return nullptr;
+    }
+
   private:
     tooling::CompileCommand Command;
   };

>From e71bdadea1602d5ed14bf6b2710a4b812f1134ad Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Sun, 24 May 2026 20:54:24 -0700
Subject: [PATCH 11/12] Undo format changes

---
 clang-tools-extra/clangd/ClangdLSPServer.cpp | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 95a6b267ed664..d42e8eff554e5 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -136,9 +136,10 @@ CodeAction toCodeAction(const Fix &F, const URIForFile &File,
     Edit.textDocument = VersionedTextDocumentIdentifier{{File}, Version};
     for (const auto &E : F.Edits)
       Edit.edits.push_back(
-          {E.range, E.newText, SupportChangeAnnotation ? E.annotationId : ""});
+          {E.range, E.newText,
+           SupportChangeAnnotation ? E.annotationId : ""});
     if (SupportChangeAnnotation) {
-      for (const auto &[AID, Annotation] : F.Annotations)
+      for (const auto &[AID, Annotation]: F.Annotations)
         Action.edit->changeAnnotations[AID] = Annotation;
     }
   }
@@ -1068,7 +1069,7 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
   std::map<ClangdServer::DiagRef, clangd::Diagnostic> ToLSPDiags;
   ClangdServer::CodeActionInputs Inputs;
 
-  for (const auto &LSPDiag : Params.context.diagnostics) {
+  for (const auto& LSPDiag : Params.context.diagnostics) {
     if (auto DiagRef = getDiagRef(File.file(), LSPDiag)) {
       ToLSPDiags[*DiagRef] = LSPDiag;
       Inputs.Diagnostics.push_back(*DiagRef);
@@ -1077,9 +1078,13 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
   Inputs.File = File.file();
   Inputs.Selection = Params.range;
   Inputs.RequestedActionKinds = Params.context.only;
-  Inputs.TweakFilter = [this](const Tweak &T) { return Opts.TweakFilter(T); };
-  auto CB = [this, Reply = std::move(Reply), ToLSPDiags = std::move(ToLSPDiags),
-             File, Selection = Params.range](
+  Inputs.TweakFilter = [this](const Tweak &T) {
+    return Opts.TweakFilter(T);
+  };
+  auto CB = [this,
+             Reply = std::move(Reply),
+             ToLSPDiags = std::move(ToLSPDiags), File,
+             Selection = Params.range](
                 llvm::Expected<ClangdServer::CodeActionResult> Fixits) mutable {
     if (!Fixits)
       return Reply(Fixits.takeError());
@@ -1088,7 +1093,8 @@ void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
     for (const auto &QF : Fixits->QuickFixes) {
       CAs.push_back(toCodeAction(QF.F, File, Version, SupportsDocumentChanges,
                                  SupportsChangeAnnotation));
-      if (auto It = ToLSPDiags.find(QF.Diag); It != ToLSPDiags.end()) {
+      if (auto It = ToLSPDiags.find(QF.Diag);
+          It != ToLSPDiags.end()) {
         CAs.back().diagnostics = {It->second};
       }
     }

>From 5ad034296e36750e32ed1609bc06571260d52e7e Mon Sep 17 00:00:00 2001
From: mwasplund <mwasplund at outlook.com>
Date: Sun, 24 May 2026 21:02:13 -0700
Subject: [PATCH 12/12] Revert remaining auto style updates

---
 clang/lib/Tooling/CommonOptionsParser.cpp     | 10 ++--
 clang/lib/Tooling/CompilationDatabase.cpp     | 27 +++++----
 .../InterpolatingCompilationDatabase.cpp      | 13 +++--
 clang/lib/Tooling/JSONCompilationDatabase.cpp | 56 ++++++++-----------
 4 files changed, 49 insertions(+), 57 deletions(-)

diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp
index 980b38bc0f4d6..c8c3ca98323e2 100644
--- a/clang/lib/Tooling/CommonOptionsParser.cpp
+++ b/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -57,12 +57,13 @@ void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
   Adjusters.push_back(std::move(Adjuster));
 }
 
-std::vector<CompileCommand>
-ArgumentsAdjustingCompilations::getCompileCommands(StringRef FilePath) const {
+std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
+    StringRef FilePath) const {
   return adjustCommands(Compilations->getCompileCommands(FilePath));
 }
 
-std::vector<std::string> ArgumentsAdjustingCompilations::getAllFiles() const {
+std::vector<std::string>
+ArgumentsAdjustingCompilations::getAllFiles() const {
   return Compilations->getAllFiles();
 }
 
@@ -139,7 +140,8 @@ llvm::Error CommonOptionsParser::init(
     }
   }
   auto AdjustingCompilations =
-      std::make_unique<ArgumentsAdjustingCompilations>(std::move(Compilations));
+      std::make_unique<ArgumentsAdjustingCompilations>(
+          std::move(Compilations));
   Adjuster =
       getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
   Adjuster = combineAdjusters(
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index 187e1223f5cef..20b9d6feb5036 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -84,8 +84,7 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
 
     if (!HasErrorMessage) {
       ErrorStream << "No compilation database found in " << Directory.str()
-                  << " or any parent directory\n"
-                  << LoadErrorMessage;
+                  << " or any parent directory\n" << LoadErrorMessage;
       HasErrorMessage = true;
     }
 
@@ -106,8 +105,7 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
 
   if (!DB)
     ErrorMessage = ("Could not auto-detect compilation database for file \"" +
-                    SourceFile + "\"\n" + ErrorMessage)
-                       .str();
+                   SourceFile + "\"\n" + ErrorMessage).str();
   return DB;
 }
 
@@ -120,10 +118,8 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
       findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
 
   if (!DB)
-    ErrorMessage =
-        ("Could not auto-detect compilation database from directory \"" +
-         SourceDir + "\"\n" + ErrorMessage)
-            .str();
+    ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
+                   SourceDir + "\"\n" + ErrorMessage).str();
   return DB;
 }
 
@@ -145,7 +141,9 @@ namespace {
 struct CompileJobAnalyzer {
   SmallVector<std::string, 2> Inputs;
 
-  void run(const driver::Action *A) { runImpl(A, false); }
+  void run(const driver::Action *A) {
+    runImpl(A, false);
+  }
 
 private:
   void runImpl(const driver::Action *A, bool Collect) {
@@ -200,7 +198,7 @@ class UnusedInputDiagConsumer : public DiagnosticConsumer {
 // They are not used for syntax checking, and could confuse targets
 // which don't support these options.
 struct FilterUnusedFlags {
-  bool operator()(StringRef S) {
+  bool operator() (StringRef S) {
     return (S == "-no-integrated-as") || S.starts_with("-Wa,");
   }
 };
@@ -368,10 +366,11 @@ FixedCompilationDatabase::loadFromBuffer(StringRef Directory, StringRef Data,
 FixedCompilationDatabase::FixedCompilationDatabase(
     const Twine &Directory, ArrayRef<std::string> CommandLine) {
   std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
-  ToolCommandLine.insert(ToolCommandLine.end(), CommandLine.begin(),
-                         CommandLine.end());
+  ToolCommandLine.insert(ToolCommandLine.end(),
+                         CommandLine.begin(), CommandLine.end());
   CompileCommands.emplace_back(Directory, StringRef(),
-                               std::move(ToolCommandLine), StringRef());
+                               std::move(ToolCommandLine),
+                               StringRef());
 }
 
 std::vector<CompileCommand>
@@ -396,7 +395,7 @@ class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
 } // namespace
 
 static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
-    X("fixed-compilation-database", "Reads plain-text flags file");
+X("fixed-compilation-database", "Reads plain-text flags file");
 
 namespace clang {
 namespace tooling {
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index a7d59f22f6015..1e6a8af1aaf79 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -201,9 +201,10 @@ struct TransferableCommand {
 
       // Strip input and output files.
       if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
-          (ClangCLMode &&
-           (Opt.matches(OPT__SLASH_Fa) || Opt.matches(OPT__SLASH_Fe) ||
-            Opt.matches(OPT__SLASH_Fi) || Opt.matches(OPT__SLASH_Fo))))
+          (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
+                           Opt.matches(OPT__SLASH_Fe) ||
+                           Opt.matches(OPT__SLASH_Fi) ||
+                           Opt.matches(OPT__SLASH_Fo))))
         continue;
 
       // ...including when the inputs are passed after --.
@@ -223,8 +224,8 @@ struct TransferableCommand {
         continue;
       }
 
-      Cmd.CommandLine.insert(Cmd.CommandLine.end(), OldArgs.data() + OldPos,
-                             OldArgs.data() + Pos);
+      Cmd.CommandLine.insert(Cmd.CommandLine.end(),
+                             OldArgs.data() + OldPos, OldArgs.data() + Pos);
     }
 
     // Make use of -std iff -x was missing.
@@ -543,7 +544,7 @@ class FileIndex {
   StringSaver Strings;
   // Indexes of candidates by certain substrings.
   // String is lowercase and sorted, index points into OriginalPaths.
-  std::vector<SubstringAndIndex> Paths; // Full path.
+  std::vector<SubstringAndIndex> Paths;      // Full path.
   // Lang types obtained by guessing on the corresponding path. I-th element is
   // a type for the I-th path.
   std::vector<types::ID> Types;
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 9155b01f3fe13..d3091ccea2779 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -45,9 +45,9 @@ namespace {
 /// Assumes \-escaping for quoted arguments (see the documentation of
 /// unescapeCommandLine(...)).
 class CommandLineArgumentParser {
-public:
+ public:
   CommandLineArgumentParser(StringRef CommandLine)
-      : Input(CommandLine), Position(Input.begin() - 1) {}
+      : Input(CommandLine), Position(Input.begin()-1) {}
 
   std::vector<std::string> parse() {
     bool HasMoreInput = true;
@@ -59,56 +59,46 @@ class CommandLineArgumentParser {
     return CommandLine;
   }
 
-private:
+ private:
   // All private methods return true if there is more input available.
 
   bool parseStringInto(std::string &String) {
     do {
       if (*Position == '"') {
-        if (!parseDoubleQuotedStringInto(String))
-          return false;
+        if (!parseDoubleQuotedStringInto(String)) return false;
       } else if (*Position == '\'') {
-        if (!parseSingleQuotedStringInto(String))
-          return false;
+        if (!parseSingleQuotedStringInto(String)) return false;
       } else {
-        if (!parseFreeStringInto(String))
-          return false;
+        if (!parseFreeStringInto(String)) return false;
       }
     } while (*Position != ' ');
     return true;
   }
 
   bool parseDoubleQuotedStringInto(std::string &String) {
-    if (!next())
-      return false;
+    if (!next()) return false;
     while (*Position != '"') {
-      if (!skipEscapeCharacter())
-        return false;
+      if (!skipEscapeCharacter()) return false;
       String.push_back(*Position);
-      if (!next())
-        return false;
+      if (!next()) return false;
     }
     return next();
   }
 
   bool parseSingleQuotedStringInto(std::string &String) {
-    if (!next())
-      return false;
+    if (!next()) return false;
     while (*Position != '\'') {
       String.push_back(*Position);
-      if (!next())
-        return false;
+      if (!next()) return false;
     }
     return next();
   }
 
   bool parseFreeStringInto(std::string &String) {
     do {
-      if (!skipEscapeCharacter())
-        return false;
+      if (!skipEscapeCharacter()) return false;
       String.push_back(*Position);
-      if (!next())
-        return false;
+      if (!next()) return false;
     } while (*Position != ' ' && *Position != '"' && *Position != '\'');
     return true;
   }
@@ -122,8 +112,7 @@ class CommandLineArgumentParser {
 
   bool nextNonWhitespace() {
     do {
-      if (!next())
-        return false;
+      if (!next()) return false;
     } while (*Position == ' ');
     return true;
   }
@@ -183,8 +172,7 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
 // Register the JSONCompilationDatabasePlugin with the
 // CompilationDatabasePluginRegistry using this statically initialized variable.
 static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
-    X("json-compilation-database",
-      "Reads JSON formatted compilation databases");
+X("json-compilation-database", "Reads JSON formatted compilation databases");
 
 namespace clang {
 namespace tooling {
@@ -247,7 +235,8 @@ JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
   return Commands;
 }
 
-std::vector<std::string> JSONCompilationDatabase::getAllFiles() const {
+std::vector<std::string>
+JSONCompilationDatabase::getAllFiles() const {
   std::vector<std::string> Result;
   for (const auto &CommandRef : IndexByFile)
     Result.push_back(CommandRef.first().str());
@@ -323,10 +312,11 @@ void JSONCompilationDatabase::getCommands(
     SmallString<32> FilenameStorage;
     SmallString<32> OutputStorage;
     auto Output = std::get<3>(CommandRef);
-    Commands.emplace_back(std::get<0>(CommandRef)->getValue(DirectoryStorage),
-                          std::get<1>(CommandRef)->getValue(FilenameStorage),
-                          nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
-                          Output ? Output->getValue(OutputStorage) : "");
+    Commands.emplace_back(
+        std::get<0>(CommandRef)->getValue(DirectoryStorage),
+        std::get<1>(CommandRef)->getValue(FilenameStorage),
+        nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
+        Output ? Output->getValue(OutputStorage) : "");
   }
 }
 
@@ -356,7 +346,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
     std::optional<std::vector<llvm::yaml::ScalarNode *>> Command;
     llvm::yaml::ScalarNode *File = nullptr;
     llvm::yaml::ScalarNode *Output = nullptr;
-    for (auto &NextKeyValue : *Object) {
+    for (auto& NextKeyValue : *Object) {
       auto *KeyString =
           dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
       if (!KeyString) {



More information about the cfe-commits mailing list