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