llvm-project/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
Serge Pavlov 6e491c48d6 [Support] Class for response file expansion (NFC)
Functions that implement expansion of response and config files depend
on many options, which are passes as arguments. Extending the expansion
requires new options, it in turn causes changing calls in various places
making them even more bulky.

This change introduces a class ExpansionContext, which represents set of
options that control the expansion. Its methods implements expansion of
responce files including config files. It makes extending the expansion
easier.

No functional changes.

Differential Revision: https://reviews.llvm.org/D132379
2022-09-28 11:47:59 +07:00

94 lines
3.1 KiB
C++

//===- 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/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Host.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<CompilationDatabase> Base,
llvm::cl::TokenizerCallback Tokenizer,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> 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<std::string> getAllFiles() const override {
return Base->getAllFiles();
}
std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const override {
return expand(Base->getCompileCommands(FilePath));
}
std::vector<CompileCommand> getAllCompileCommands() const override {
return expand(Base->getAllCompileCommands());
}
private:
std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const {
for (auto &Cmd : Cmds) {
bool SeenRSPFile = false;
llvm::SmallVector<const char *, 20> Argv;
Argv.reserve(Cmd.CommandLine.size());
for (auto &Arg : Cmd.CommandLine) {
Argv.push_back(Arg.c_str());
if (!Arg.empty())
SeenRSPFile |= Arg.front() == '@';
}
if (!SeenRSPFile)
continue;
llvm::BumpPtrAllocator Alloc;
llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
ECtx.setVFS(FS.get())
.setCurrentDir(Cmd.Directory)
.expandResponseFiles(Argv);
// Don't assign directly, Argv aliases CommandLine.
std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
Cmd.CommandLine = std::move(ExpandedArgv);
}
return Cmds;
}
private:
std::unique_ptr<CompilationDatabase> Base;
llvm::cl::TokenizerCallback Tokenizer;
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
};
} // namespace
std::unique_ptr<CompilationDatabase>
expandResponseFiles(std::unique_ptr<CompilationDatabase> Base,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows()
? llvm::cl::TokenizeWindowsCommandLine
: llvm::cl::TokenizeGNUCommandLine;
return std::make_unique<ExpandResponseFilesDatabase>(
std::move(Base), Tokenizer, std::move(FS));
}
} // namespace tooling
} // namespace clang