Previously an error raised during an expansion of response files (including configuration files) was ignored and only the fact of its presence was reported to the user with generic error messages. This made it difficult to analyze problems. For example, if a configuration file tried to read an inexistent file, the error message said that 'configuration file cannot be found', which is wrong and misleading. This change enhances handling errors in the expansion so that users could get more informative error messages. Differential Revision: https://reviews.llvm.org/D136090
96 lines
3.2 KiB
C++
96 lines
3.2 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);
|
|
llvm::Error Err = ECtx.setVFS(FS.get())
|
|
.setCurrentDir(Cmd.Directory)
|
|
.expandResponseFiles(Argv);
|
|
if (Err)
|
|
llvm::errs() << Err;
|
|
// 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
|