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

via cfe-commits cfe-commits at lists.llvm.org
Sun Dec 31 00:54:01 PST 2023


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

>From 071f8df3f82798255bcc0e2787fd7167b607d59f Mon Sep 17 00:00:00 2001
From: Overhatted <15021741+Overhatted at users.noreply.github.com>
Date: Fri, 15 Dec 2023 15:53:56 +0000
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 ++++++++++++++-----
 .../Tooling/CompilationDatabaseTest.cpp       | 10 ++++----
 5 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 5bec7966a9c3a9..de017b78241ad3 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -245,7 +245,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)) {
     // 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/docs/JSONCompilationDatabase.rst b/clang/docs/JSONCompilationDatabase.rst
index f5432278bd4d4e..41219a554dfdea 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 96582457c63d58..3ec0e36c196d2e 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 a77686996879f1..c8c7f46e1fb3e6 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 {
diff --git a/clang/unittests/Tooling/CompilationDatabaseTest.cpp b/clang/unittests/Tooling/CompilationDatabaseTest.cpp
index 5173d472486bfc..9479d02532def2 100644
--- a/clang/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/clang/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -27,8 +27,8 @@ using testing::UnorderedElementsAreArray;
 static void expectFailure(StringRef JSONDatabase, StringRef Explanation) {
   std::string ErrorMessage;
   EXPECT_EQ(nullptr,
-            JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
-                                                    JSONCommandLineSyntax::Gnu))
+            JSONCompilationDatabase::loadFromBuffer(
+                "", JSONDatabase, ErrorMessage, JSONCommandLineSyntax::Gnu))
       << "Expected an error because of: " << Explanation.str();
 }
 
@@ -56,7 +56,7 @@ static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
                                             std::string &ErrorMessage,
                                             JSONCommandLineSyntax Syntax) {
   std::unique_ptr<CompilationDatabase> Database(
-      JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+      JSONCompilationDatabase::loadFromBuffer("", JSONDatabase, ErrorMessage,
                                               Syntax));
   if (!Database) {
     ADD_FAILURE() << ErrorMessage;
@@ -71,7 +71,7 @@ static std::vector<CompileCommand>
 getAllCompileCommands(JSONCommandLineSyntax Syntax, StringRef JSONDatabase,
                       std::string &ErrorMessage) {
   std::unique_ptr<CompilationDatabase> Database(
-      JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+      JSONCompilationDatabase::loadFromBuffer("", JSONDatabase, ErrorMessage,
                                               Syntax));
   if (!Database) {
     ADD_FAILURE() << ErrorMessage;
@@ -193,7 +193,7 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
                                                     std::string JSONDatabase,
                                                     std::string &ErrorMessage) {
   std::unique_ptr<CompilationDatabase> Database(
-      JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+      JSONCompilationDatabase::loadFromBuffer("", JSONDatabase, ErrorMessage,
                                               JSONCommandLineSyntax::Gnu));
   if (!Database)
     return CompileCommand();



More information about the cfe-commits mailing list