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