diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 5bec7966a9c3a..de017b78241ad 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 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 f5432278bd4d4..41219a554dfde 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 96582457c63d5..3ec0e36c196d2 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 - 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 Database, + JSONCompilationDatabase(SmallString<128> FolderPath, + std::unique_ptr 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 Database; JSONCommandLineSyntax Syntax; llvm::SourceMgr SM; diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index a77686996879f..c8c7f46e1fb3e 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 Database( - new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax)); + SmallString<128> FolderPath = FilePath; + llvm::sys::path::remove_filename(FolderPath); + std::unique_ptr Database(new JSONCompilationDatabase( + FolderPath, std::move(*DatabaseBuffer), Syntax)); if (!Database->parse(ErrorMessage)) return nullptr; return Database; } std::unique_ptr -JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString, +JSONCompilationDatabase::loadFromBuffer(StringRef FilePath, + StringRef DatabaseString, std::string &ErrorMessage, JSONCommandLineSyntax Syntax) { std::unique_ptr DatabaseBuffer( llvm::MemoryBuffer::getMemBufferCopy(DatabaseString)); - std::unique_ptr Database( - new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax)); + SmallString<128> FolderPath = FilePath; + llvm::sys::path::remove_filename(FolderPath); + std::unique_ptr 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 45062cf7c16f6..31a81e675f973 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 getAllFiles(StringRef JSONDatabase, std::string &ErrorMessage, JSONCommandLineSyntax Syntax) { std::unique_ptr Database( - JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage, + JSONCompilationDatabase::loadFromBuffer("", JSONDatabase, ErrorMessage, Syntax)); if (!Database) { ADD_FAILURE() << ErrorMessage; @@ -71,7 +71,7 @@ static std::vector getAllCompileCommands(JSONCommandLineSyntax Syntax, StringRef JSONDatabase, std::string &ErrorMessage) { std::unique_ptr 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 Database( - JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage, + JSONCompilationDatabase::loadFromBuffer("", JSONDatabase, ErrorMessage, JSONCommandLineSyntax::Gnu)); if (!Database) return CompileCommand();