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