[clang-tools-extra] In compilation databases, add support for relative directories (PR #69856)

via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 21 12:48:43 PDT 2023


https://github.com/Overhatted created https://github.com/llvm/llvm-project/pull/69856

I haven't finished all of the tests and formatting so it's a bit in a POC stage but I would like to know if this change would be accepted.

The change is to support relative paths in the "directory" field in compilation databases. At the moment the specification doesn't seem to explicitly dissallow it but the implementation doesn't support it.

The use-case is I'm using Buck2 to generate the compilation databases which produces them with a "." for the directory field. Of course it could be changed on the Buck2 side but I think it would be useful to simply support relative paths on the clang side since it allows caching of the compilation database or maybe even commiting it to the repository.

Please let me know if this is an acceptable change or not.

>From dcef5e88eb1cdcdf896eebb4773f456ed2d87055 Mon Sep 17 00:00:00 2001
From: Overhatted <15021741+Overhatted at users.noreply.github.com>
Date: Sat, 21 Oct 2023 14:16:38 +0100
Subject: [PATCH] In compilation databases, add support for relative
 directories

---
 .../clangd/GlobalCompilationDatabase.cpp      |  2 +-
 clang/docs/JSONCompilationDatabase.rst        |  4 +++-
 .../clang/Tooling/JSONCompilationDatabase.h   | 10 ++++----
 clang/lib/Tooling/JSONCompilationDatabase.cpp | 24 ++++++++++++++-----
 4 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index d1833759917a30f..3e81308316d55cd 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -243,7 +243,7 @@ DirectoryBasedGlobalCompilationDatabase::DirectoryCache::CachedFile::load(
 static std::unique_ptr<tooling::CompilationDatabase>
 parseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) {
   if (auto CDB = tooling::JSONCompilationDatabase::loadFromBuffer(
-          Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
+          Path, Data, Error, tooling::JSONCommandLineSyntax::AutoDetect)) {
     return tooling::inferMissingCompileCommands(std::move(CDB));
   }
   return nullptr;
diff --git a/clang/docs/JSONCompilationDatabase.rst b/clang/docs/JSONCompilationDatabase.rst
index f5432278bd4d4e4..41219a554dfdeaa 100644
--- a/clang/docs/JSONCompilationDatabase.rst
+++ b/clang/docs/JSONCompilationDatabase.rst
@@ -81,7 +81,9 @@ The contracts for each field in the command object are:
 
 -  **directory:** The working directory of the compilation. All paths
    specified in the **command** or **file** fields must be either
-   absolute or relative to this directory.
+   absolute or relative to this directory. This field itself can be a
+   relative path in which case it is evaluated relative to the folder
+   containing the compilation database file.
 -  **file:** The main translation unit source processed by this
    compilation step. This is used by tools as the key into the
    compilation database. There can be multiple command objects for the
diff --git a/clang/include/clang/Tooling/JSONCompilationDatabase.h b/clang/include/clang/Tooling/JSONCompilationDatabase.h
index 96582457c63d588..3ec0e36c196d2e4 100644
--- a/clang/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/clang/include/clang/Tooling/JSONCompilationDatabase.h
@@ -72,8 +72,8 @@ class JSONCompilationDatabase : public CompilationDatabase {
   ///
   /// Returns NULL and sets ErrorMessage if the database could not be loaded.
   static std::unique_ptr<JSONCompilationDatabase>
-  loadFromBuffer(StringRef DatabaseString, std::string &ErrorMessage,
-                 JSONCommandLineSyntax Syntax);
+  loadFromBuffer(StringRef FilePath, StringRef DatabaseString,
+                 std::string &ErrorMessage, JSONCommandLineSyntax Syntax);
 
   /// Returns all compile commands in which the specified file was
   /// compiled.
@@ -94,9 +94,10 @@ class JSONCompilationDatabase : public CompilationDatabase {
 
 private:
   /// Constructs a JSON compilation database on a memory buffer.
-  JSONCompilationDatabase(std::unique_ptr<llvm::MemoryBuffer> Database,
+  JSONCompilationDatabase(SmallString<128> FolderPath,
+                          std::unique_ptr<llvm::MemoryBuffer> Database,
                           JSONCommandLineSyntax Syntax)
-      : Database(std::move(Database)), Syntax(Syntax),
+      : FolderPath(FolderPath), Database(std::move(Database)), Syntax(Syntax),
         YAMLStream(this->Database->getBuffer(), SM) {}
 
   /// Parses the database file and creates the index.
@@ -130,6 +131,7 @@ class JSONCompilationDatabase : public CompilationDatabase {
 
   FileMatchTrie MatchTrie;
 
+  SmallString<128> FolderPath;
   std::unique_ptr<llvm::MemoryBuffer> Database;
   JSONCommandLineSyntax Syntax;
   llvm::SourceMgr SM;
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index a77686996879f1d..c8c7f46e1fb3e66 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -202,21 +202,26 @@ JSONCompilationDatabase::loadFromFile(StringRef FilePath,
     ErrorMessage = "Error while opening JSON database: " + Result.message();
     return nullptr;
   }
-  std::unique_ptr<JSONCompilationDatabase> Database(
-      new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
+  SmallString<128> FolderPath = FilePath;
+  llvm::sys::path::remove_filename(FolderPath);
+  std::unique_ptr<JSONCompilationDatabase> Database(new JSONCompilationDatabase(
+      FolderPath, std::move(*DatabaseBuffer), Syntax));
   if (!Database->parse(ErrorMessage))
     return nullptr;
   return Database;
 }
 
 std::unique_ptr<JSONCompilationDatabase>
-JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
+JSONCompilationDatabase::loadFromBuffer(StringRef FilePath,
+                                        StringRef DatabaseString,
                                         std::string &ErrorMessage,
                                         JSONCommandLineSyntax Syntax) {
   std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
       llvm::MemoryBuffer::getMemBufferCopy(DatabaseString));
-  std::unique_ptr<JSONCompilationDatabase> Database(
-      new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
+  SmallString<128> FolderPath = FilePath;
+  llvm::sys::path::remove_filename(FolderPath);
+  std::unique_ptr<JSONCompilationDatabase> Database(new JSONCompilationDatabase(
+      FolderPath, std::move(DatabaseBuffer), Syntax));
   if (!Database->parse(ErrorMessage))
     return nullptr;
   return Database;
@@ -419,7 +424,14 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
     SmallString<128> NativeFilePath;
     if (llvm::sys::path::is_relative(FileName)) {
       SmallString<8> DirectoryStorage;
-      SmallString<128> AbsolutePath(Directory->getValue(DirectoryStorage));
+      StringRef DirectoryName = Directory->getValue(DirectoryStorage);
+      SmallString<128> AbsolutePath;
+      if (llvm::sys::path::is_relative(DirectoryName)) {
+        AbsolutePath = FolderPath;
+        llvm::sys::path::append(AbsolutePath, DirectoryName);
+      } else {
+        AbsolutePath = DirectoryName;
+      }
       llvm::sys::path::append(AbsolutePath, FileName);
       llvm::sys::path::native(AbsolutePath, NativeFilePath);
     } else {



More information about the cfe-commits mailing list