From 45ef055d4ffda4d2b04b62f73e36cc6d5252758b Mon Sep 17 00:00:00 2001 From: Kadir Cetinkaya Date: Fri, 29 Nov 2019 12:14:25 +0100 Subject: [PATCH] [clang][Tooling] Add support for .rsp files in compile_commands.json Summary: Add support for .rsp files. Fixes https://github.com/clangd/clangd/issues/81 Patch By: liu hui(@lh123) Reviewers: sammccall, ilya-biryukov, hokein, kadircet Reviewed By: kadircet Subscribers: merge_guards_bot, mgorny, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang-tools-extra, #clang Differential Revision: https://reviews.llvm.org/D70222 --- clang/include/clang/Tooling/CompilationDatabase.h | 8 ++ clang/lib/Tooling/CMakeLists.txt | 1 + .../ExpandResponseFilesCompilationDatabase.cpp | 92 ++++++++++++++++++++++ clang/lib/Tooling/JSONCompilationDatabase.cpp | 4 +- .../unittests/Tooling/CompilationDatabaseTest.cpp | 30 +++++++ 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp diff --git a/clang/include/clang/Tooling/CompilationDatabase.h b/clang/include/clang/Tooling/CompilationDatabase.h index dea046a..6f794e5 100644 --- a/clang/include/clang/Tooling/CompilationDatabase.h +++ b/clang/include/clang/Tooling/CompilationDatabase.h @@ -31,6 +31,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include #include @@ -219,6 +220,13 @@ std::unique_ptr std::unique_ptr inferTargetAndDriverMode(std::unique_ptr Base); +/// Returns a wrapped CompilationDatabase that will expand all rsp(response) +/// files on commandline returned by underlying database. +/// Note: This may change the working directory of FS. +std::unique_ptr +expandResponseFiles(std::unique_ptr Base, + llvm::IntrusiveRefCntPtr FS); + } // namespace tooling } // namespace clang diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt index 05061f0..59c990d 100644 --- a/clang/lib/Tooling/CMakeLists.txt +++ b/clang/lib/Tooling/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangTooling CommonOptionsParser.cpp CompilationDatabase.cpp Execution.cpp + ExpandResponseFilesCompilationDatabase.cpp FileMatchTrie.cpp FixIt.cpp GuessTargetAndModeCompilationDatabase.cpp diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp new file mode 100644 index 0000000..bb51927 --- /dev/null +++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp @@ -0,0 +1,92 @@ +//===- ExpandResponseFileCompilationDataBase.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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" + +namespace clang { +namespace tooling { +namespace { + +class ExpandResponseFilesDatabase : public CompilationDatabase { +public: + ExpandResponseFilesDatabase( + std::unique_ptr Base, + llvm::cl::TokenizerCallback Tokenizer, + llvm::IntrusiveRefCntPtr FS) + : Base(std::move(Base)), Tokenizer(Tokenizer), FS(std::move(FS)) { + assert(this->Base != nullptr); + assert(this->Tokenizer != nullptr); + assert(this->FS != nullptr); + } + + std::vector getAllFiles() const override { + return Base->getAllFiles(); + } + + std::vector + getCompileCommands(StringRef FilePath) const override { + return expand(Base->getCompileCommands(FilePath)); + } + + std::vector getAllCompileCommands() const override { + return expand(Base->getAllCompileCommands()); + } + +private: + std::vector expand(std::vector Cmds) const { + for (auto &Cmd : Cmds) { + // FIXME: we should rather propagate the current directory into + // ExpandResponseFiles as well in addition to FS. + if (std::error_code EC = FS->setCurrentWorkingDirectory(Cmd.Directory)) { + llvm::consumeError(llvm::errorCodeToError(EC)); + continue; + } + bool SeenRSPFile = false; + llvm::SmallVector Argv; + Argv.reserve(Cmd.CommandLine.size()); + for (auto &Arg : Cmd.CommandLine) { + Argv.push_back(Arg.c_str()); + SeenRSPFile |= Arg.front() == '@'; + } + if (!SeenRSPFile) + continue; + llvm::BumpPtrAllocator Alloc; + llvm::StringSaver Saver(Alloc); + llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, *FS); + Cmd.CommandLine.assign(Argv.begin(), Argv.end()); + } + return Cmds; + } + +private: + std::unique_ptr Base; + llvm::cl::TokenizerCallback Tokenizer; + llvm::IntrusiveRefCntPtr FS; +}; + +} // namespace + +std::unique_ptr +expandResponseFiles(std::unique_ptr Base, + llvm::IntrusiveRefCntPtr FS) { + auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows() + ? llvm::cl::TokenizeWindowsCommandLine + : llvm::cl::TokenizeGNUCommandLine; + return std::make_unique( + std::move(Base), Tokenizer, std::move(FS)); +} + +} // namespace tooling +} // namespace clang diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index f19a0f7..8dd4608 100644 --- a/clang/lib/Tooling/JSONCompilationDatabase.cpp +++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp @@ -168,7 +168,9 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin { auto Base = JSONCompilationDatabase::loadFromFile( JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect); return Base ? inferTargetAndDriverMode( - inferMissingCompileCommands(std::move(Base))) + inferMissingCompileCommands(expandResponseFiles( + std::move(Base), + llvm::vfs::createPhysicalFileSystem().release()))) : nullptr; } }; diff --git a/clang/unittests/Tooling/CompilationDatabaseTest.cpp b/clang/unittests/Tooling/CompilationDatabaseTest.cpp index 87727fe..91685c0 100644 --- a/clang/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/clang/unittests/Tooling/CompilationDatabaseTest.cpp @@ -859,5 +859,35 @@ TEST_F(TargetAndModeTest, TargetAndMode) { "clang++ --driver-mode=g++ bar.cpp -D bar.cpp"); } +class ExpandResponseFilesTest : public MemDBTest { +public: + ExpandResponseFilesTest() : FS(new llvm::vfs::InMemoryFileSystem) {} + +protected: + void addFile(StringRef File, StringRef Content) { + ASSERT_TRUE( + FS->addFile(File, 0, llvm::MemoryBuffer::getMemBufferCopy(Content))); + } + + std::string getCommand(llvm::StringRef F) { + auto Results = expandResponseFiles(std::make_unique(Entries), FS) + ->getCompileCommands(path(F)); + if (Results.empty()) + return "none"; + return llvm::join(Results[0].CommandLine, " "); + } + + llvm::IntrusiveRefCntPtr FS; +}; + +TEST_F(ExpandResponseFilesTest, ExpandResponseFiles) { + addFile(path(StringRef("rsp1.rsp")), "-Dflag"); + + add("foo.cpp", "clang", "@rsp1.rsp"); + add("bar.cpp", "clang", "-Dflag"); + EXPECT_EQ(getCommand("foo.cpp"), "clang foo.cpp -D foo.cpp -Dflag"); + EXPECT_EQ(getCommand("bar.cpp"), "clang bar.cpp -D bar.cpp -Dflag"); +} + } // end namespace tooling } // end namespace clang -- 2.7.4