1*45ef055dSKadir Cetinkaya //===- ExpandResponseFileCompilationDataBase.cpp --------------------------===// 2*45ef055dSKadir Cetinkaya // 3*45ef055dSKadir Cetinkaya // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*45ef055dSKadir Cetinkaya // See https://llvm.org/LICENSE.txt for license information. 5*45ef055dSKadir Cetinkaya // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*45ef055dSKadir Cetinkaya // 7*45ef055dSKadir Cetinkaya //===----------------------------------------------------------------------===// 8*45ef055dSKadir Cetinkaya 9*45ef055dSKadir Cetinkaya #include "clang/Tooling/CompilationDatabase.h" 10*45ef055dSKadir Cetinkaya #include "llvm/ADT/Triple.h" 11*45ef055dSKadir Cetinkaya #include "llvm/Support/CommandLine.h" 12*45ef055dSKadir Cetinkaya #include "llvm/Support/ConvertUTF.h" 13*45ef055dSKadir Cetinkaya #include "llvm/Support/ErrorOr.h" 14*45ef055dSKadir Cetinkaya #include "llvm/Support/MemoryBuffer.h" 15*45ef055dSKadir Cetinkaya #include "llvm/Support/Path.h" 16*45ef055dSKadir Cetinkaya #include "llvm/Support/StringSaver.h" 17*45ef055dSKadir Cetinkaya 18*45ef055dSKadir Cetinkaya namespace clang { 19*45ef055dSKadir Cetinkaya namespace tooling { 20*45ef055dSKadir Cetinkaya namespace { 21*45ef055dSKadir Cetinkaya 22*45ef055dSKadir Cetinkaya class ExpandResponseFilesDatabase : public CompilationDatabase { 23*45ef055dSKadir Cetinkaya public: 24*45ef055dSKadir Cetinkaya ExpandResponseFilesDatabase( 25*45ef055dSKadir Cetinkaya std::unique_ptr<CompilationDatabase> Base, 26*45ef055dSKadir Cetinkaya llvm::cl::TokenizerCallback Tokenizer, 27*45ef055dSKadir Cetinkaya llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 28*45ef055dSKadir Cetinkaya : Base(std::move(Base)), Tokenizer(Tokenizer), FS(std::move(FS)) { 29*45ef055dSKadir Cetinkaya assert(this->Base != nullptr); 30*45ef055dSKadir Cetinkaya assert(this->Tokenizer != nullptr); 31*45ef055dSKadir Cetinkaya assert(this->FS != nullptr); 32*45ef055dSKadir Cetinkaya } 33*45ef055dSKadir Cetinkaya 34*45ef055dSKadir Cetinkaya std::vector<std::string> getAllFiles() const override { 35*45ef055dSKadir Cetinkaya return Base->getAllFiles(); 36*45ef055dSKadir Cetinkaya } 37*45ef055dSKadir Cetinkaya 38*45ef055dSKadir Cetinkaya std::vector<CompileCommand> 39*45ef055dSKadir Cetinkaya getCompileCommands(StringRef FilePath) const override { 40*45ef055dSKadir Cetinkaya return expand(Base->getCompileCommands(FilePath)); 41*45ef055dSKadir Cetinkaya } 42*45ef055dSKadir Cetinkaya 43*45ef055dSKadir Cetinkaya std::vector<CompileCommand> getAllCompileCommands() const override { 44*45ef055dSKadir Cetinkaya return expand(Base->getAllCompileCommands()); 45*45ef055dSKadir Cetinkaya } 46*45ef055dSKadir Cetinkaya 47*45ef055dSKadir Cetinkaya private: 48*45ef055dSKadir Cetinkaya std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const { 49*45ef055dSKadir Cetinkaya for (auto &Cmd : Cmds) { 50*45ef055dSKadir Cetinkaya // FIXME: we should rather propagate the current directory into 51*45ef055dSKadir Cetinkaya // ExpandResponseFiles as well in addition to FS. 52*45ef055dSKadir Cetinkaya if (std::error_code EC = FS->setCurrentWorkingDirectory(Cmd.Directory)) { 53*45ef055dSKadir Cetinkaya llvm::consumeError(llvm::errorCodeToError(EC)); 54*45ef055dSKadir Cetinkaya continue; 55*45ef055dSKadir Cetinkaya } 56*45ef055dSKadir Cetinkaya bool SeenRSPFile = false; 57*45ef055dSKadir Cetinkaya llvm::SmallVector<const char *, 20> Argv; 58*45ef055dSKadir Cetinkaya Argv.reserve(Cmd.CommandLine.size()); 59*45ef055dSKadir Cetinkaya for (auto &Arg : Cmd.CommandLine) { 60*45ef055dSKadir Cetinkaya Argv.push_back(Arg.c_str()); 61*45ef055dSKadir Cetinkaya SeenRSPFile |= Arg.front() == '@'; 62*45ef055dSKadir Cetinkaya } 63*45ef055dSKadir Cetinkaya if (!SeenRSPFile) 64*45ef055dSKadir Cetinkaya continue; 65*45ef055dSKadir Cetinkaya llvm::BumpPtrAllocator Alloc; 66*45ef055dSKadir Cetinkaya llvm::StringSaver Saver(Alloc); 67*45ef055dSKadir Cetinkaya llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, *FS); 68*45ef055dSKadir Cetinkaya Cmd.CommandLine.assign(Argv.begin(), Argv.end()); 69*45ef055dSKadir Cetinkaya } 70*45ef055dSKadir Cetinkaya return Cmds; 71*45ef055dSKadir Cetinkaya } 72*45ef055dSKadir Cetinkaya 73*45ef055dSKadir Cetinkaya private: 74*45ef055dSKadir Cetinkaya std::unique_ptr<CompilationDatabase> Base; 75*45ef055dSKadir Cetinkaya llvm::cl::TokenizerCallback Tokenizer; 76*45ef055dSKadir Cetinkaya llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; 77*45ef055dSKadir Cetinkaya }; 78*45ef055dSKadir Cetinkaya 79*45ef055dSKadir Cetinkaya } // namespace 80*45ef055dSKadir Cetinkaya 81*45ef055dSKadir Cetinkaya std::unique_ptr<CompilationDatabase> 82*45ef055dSKadir Cetinkaya expandResponseFiles(std::unique_ptr<CompilationDatabase> Base, 83*45ef055dSKadir Cetinkaya llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) { 84*45ef055dSKadir Cetinkaya auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows() 85*45ef055dSKadir Cetinkaya ? llvm::cl::TokenizeWindowsCommandLine 86*45ef055dSKadir Cetinkaya : llvm::cl::TokenizeGNUCommandLine; 87*45ef055dSKadir Cetinkaya return std::make_unique<ExpandResponseFilesDatabase>( 88*45ef055dSKadir Cetinkaya std::move(Base), Tokenizer, std::move(FS)); 89*45ef055dSKadir Cetinkaya } 90*45ef055dSKadir Cetinkaya 91*45ef055dSKadir Cetinkaya } // namespace tooling 92*45ef055dSKadir Cetinkaya } // namespace clang 93