Index: include/clang/Tooling/CompilationDatabase.h =================================================================== --- include/clang/Tooling/CompilationDatabase.h +++ include/clang/Tooling/CompilationDatabase.h @@ -122,6 +122,11 @@ /// \brief Returns the list of all files available in the compilation database. virtual std::vector getAllFiles() const = 0; + /// \brief Returns the common build directory for all translation units in the + /// compilation database. Return None if there are different build + /// directories. + virtual llvm::Optional getCommonRoot() const = 0; + /// \brief Returns all compile commands for all the files in the compilation /// database. /// @@ -210,6 +215,10 @@ /// Note: This is always an empty list for the fixed compilation database. std::vector getAllCompileCommands() const override; + /// \brief Returns the common build directory for all translation units in the + /// compilation database. + llvm::Optional getCommonRoot() const override; + private: /// This is built up to contain a single entry vector to be returned from /// getCompileCommands after adding the positional argument. Index: include/clang/Tooling/JSONCompilationDatabase.h =================================================================== --- include/clang/Tooling/JSONCompilationDatabase.h +++ include/clang/Tooling/JSONCompilationDatabase.h @@ -90,12 +90,18 @@ /// database. std::vector getAllCompileCommands() const override; + /// \brief Returns the common build directory for all translation units in the + /// JSON compilation database. + llvm::Optional getCommonRoot() const override { + return CommonRoot; + } + private: /// \brief Constructs a JSON compilation database on a memory buffer. JSONCompilationDatabase(std::unique_ptr Database, JSONCommandLineSyntax Syntax) : Database(std::move(Database)), Syntax(Syntax), - YAMLStream(this->Database->getBuffer(), SM) {} + YAMLStream(this->Database->getBuffer(), SM), CommonRoot(llvm::None) {} /// \brief Parses the database file and creates the index. /// @@ -130,6 +136,8 @@ JSONCommandLineSyntax Syntax; llvm::SourceMgr SM; llvm::yaml::Stream YAMLStream; + + llvm::Optional CommonRoot; }; } // end namespace tooling Index: lib/Tooling/CommonOptionsParser.cpp =================================================================== --- lib/Tooling/CommonOptionsParser.cpp +++ lib/Tooling/CommonOptionsParser.cpp @@ -78,6 +78,10 @@ return adjustCommands(Compilations->getAllCompileCommands()); } + llvm::Optional getCommonRoot() const override { + return Compilations->getCommonRoot(); + } + private: std::unique_ptr Compilations; std::vector Adjusters; Index: lib/Tooling/CompilationDatabase.cpp =================================================================== --- lib/Tooling/CompilationDatabase.cpp +++ lib/Tooling/CompilationDatabase.cpp @@ -322,6 +322,17 @@ return std::vector(); } +llvm::Optional FixedCompilationDatabase::getCommonRoot() const { + auto It = + std::find_if(CompileCommands.begin(), CompileCommands.end(), + [&](const clang::tooling::CompileCommand &Command) { + return CompileCommands[0].Directory != Command.Directory; + }); + if (It == CompileCommands.end()) + return CompileCommands[0].Directory; + return llvm::None; +} + namespace clang { namespace tooling { Index: lib/Tooling/JSONCompilationDatabase.cpp =================================================================== --- lib/Tooling/JSONCompilationDatabase.cpp +++ lib/Tooling/JSONCompilationDatabase.cpp @@ -366,6 +366,20 @@ AllCommands.push_back(Cmd); MatchTrie.insert(NativeFilePath); } + if (!AllCommands.empty()) { + SmallString<128> DirectoryStorage; + SmallString<128> NextDirectoryStorage; + llvm::StringRef Directory = + std::get<0>(AllCommands[0])->getValue(DirectoryStorage); + auto It = std::find_if( + AllCommands.begin() + 1, AllCommands.end(), + [&](JSONCompilationDatabase::CompileCommandRef &Command) { + return Directory != + std::get<0>(Command)->getValue(NextDirectoryStorage); + }); + if (It == AllCommands.end()) + CommonRoot = Directory.str(); + } return true; } Index: unittests/Tooling/CompilationDatabaseTest.cpp =================================================================== --- unittests/Tooling/CompilationDatabaseTest.cpp +++ unittests/Tooling/CompilationDatabaseTest.cpp @@ -95,6 +95,34 @@ << ErrorMessage; } +TEST(JSONCompilationDatabase, GetCommonRoot) { + std::string ErrorMessage; + std::string JSONDatabase = "[{\"directory\":\"//dir/build/\"," + "\"command\":\"command\"," + "\"file\":\"file1\"}," + " {\"directory\":\"//dir/build/\"," + "\"command\":\"command\"," + "\"file\":\"file2\"}]"; + + std::unique_ptr Database( + JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage, + JSONCommandLineSyntax::Gnu)); + auto CommonRoot = Database->getCommonRoot(); + ASSERT_TRUE(CommonRoot.hasValue()); + EXPECT_EQ("//dir/build/", *CommonRoot); + + JSONDatabase = "[{\"directory\":\"//dir/build/\"," + "\"command\":\"command\"," + "\"file\":\"file1\"}," + " {\"directory\":\"//dir/build2/\"," + "\"command\":\"command\"," + "\"file\":\"file2\"}]"; + Database = JSONCompilationDatabase::loadFromBuffer( + JSONDatabase, ErrorMessage, JSONCommandLineSyntax::Gnu); + CommonRoot = Database->getCommonRoot(); + EXPECT_FALSE(CommonRoot.hasValue()); +} + TEST(JSONCompilationDatabase, GetAllCompileCommands) { std::string ErrorMessage; EXPECT_EQ(