38#include "llvm/ADT/ArrayRef.h"
39#include "llvm/ADT/IntrusiveRefCntPtr.h"
40#include "llvm/ADT/StringRef.h"
41#include "llvm/ADT/Twine.h"
42#include "llvm/Option/ArgList.h"
43#include "llvm/Option/OptTable.h"
44#include "llvm/Option/Option.h"
45#include "llvm/Support/CommandLine.h"
46#include "llvm/Support/Debug.h"
47#include "llvm/Support/ErrorHandling.h"
48#include "llvm/Support/MemoryBuffer.h"
49#include "llvm/Support/Path.h"
50#include "llvm/Support/VirtualFileSystem.h"
51#include "llvm/Support/raw_ostream.h"
52#include "llvm/TargetParser/Host.h"
57#include <system_error>
61#define DEBUG_TYPE "clang-tooling"
79 new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(),
80 *Diagnostics,
"clang LLVM compiler", std::move(VFS));
81 CompilerDriver->
setTitle(
"clang_based_tool");
82 return CompilerDriver;
90 bool OffloadCompilation =
false;
95 for (
const auto &Job : Jobs)
96 if (StringRef(Job.getExecutable()) ==
"clang-offload-bundler")
97 OffloadCompilation =
true;
99 if (Jobs.
size() > 1) {
100 for (
auto *A : Actions){
103 A = *A->input_begin();
111 assert(Actions.size() > 1);
118 OffloadCompilation =
true;
124 return OffloadCompilation;
130const llvm::opt::ArgStringList *
136 return StringRef(Cmd.getCreator().getName()) ==
"clang";
140 return isSrcFile(II.getType());
145 if (IsCC1Command(Job) && llvm::all_of(Job.getInputInfos(), IsSrcFile))
146 CC1Jobs.push_back(&Job);
152 if (IsCC1Command(Job))
153 CC1Jobs.push_back(&Job);
155 if (CC1Jobs.empty() ||
158 llvm::raw_svector_ostream error_stream(error_msg);
159 Jobs.
Print(error_stream,
"; ",
true);
160 Diagnostics->
Report(diag::err_fe_expected_compiler_job)
161 << error_stream.str();
165 return &CC1Jobs[0]->getArguments();
171 const char *
const BinaryName) {
172 assert(!CC1Args.empty() &&
"Must at least contain the program name!");
182 const Twine &Code,
const Twine &
FileName,
183 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
185 std::vector<std::string>(),
FileName,
186 "clang-tool", std::move(PCHContainerOps));
192static std::vector<std::string>
194 const std::vector<std::string> &ExtraArgs,
196 std::vector<std::string> Args;
197 Args.push_back(ToolName.str());
198 Args.push_back(
"-fsyntax-only");
199 llvm::append_range(Args, ExtraArgs);
208 std::unique_ptr<FrontendAction>
ToolAction,
const Twine &Code,
210 const std::vector<std::string> &Args,
const Twine &
FileName,
211 const Twine &ToolName,
212 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
214 StringRef FileNameRef =
FileName.toNullTerminatedStringRef(FileNameStorage);
221 std::move(
ToolAction), Files.get(), std::move(PCHContainerOps));
222 return Invocation.
run();
226 std::unique_ptr<FrontendAction>
ToolAction,
const Twine &Code,
227 const std::vector<std::string> &Args,
const Twine &
FileName,
228 const Twine &ToolName,
229 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
231 auto OverlayFileSystem =
232 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
233 llvm::vfs::getRealFileSystem());
234 auto InMemoryFileSystem =
235 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
236 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
239 InMemoryFileSystem->addFile(
FileName, 0,
240 llvm::MemoryBuffer::getMemBuffer(
241 Code.toNullTerminatedStringRef(CodeStorage)));
243 for (
auto &FilenameWithContent : VirtualMappedFiles) {
244 InMemoryFileSystem->addFile(
245 FilenameWithContent.first, 0,
246 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
255 StringRef RelativePath(
File);
257 RelativePath.consume_front(
"./");
260 if (
auto EC = FS.makeAbsolute(AbsolutePath))
261 return llvm::errorCodeToError(EC);
262 llvm::sys::path::native(AbsolutePath);
263 return std::string(AbsolutePath);
271 StringRef InvokedAs) {
272 if (CommandLine.empty() || InvokedAs.empty())
276 StringRef TargetOPT = Table.getOption(options::OPT_target).getPrefixedName();
278 StringRef TargetOPTLegacy =
279 Table.getOption(options::OPT_target_legacy_spelling).getPrefixedName();
281 StringRef DriverModeOPT =
282 Table.getOption(options::OPT_driver_mode).getPrefixedName();
286 bool ShouldAddTarget = TargetMode.TargetIsValid;
287 bool ShouldAddMode = TargetMode.DriverMode !=
nullptr;
289 for (
auto Token = ++CommandLine.begin();
Token != CommandLine.end();
291 StringRef TokenRef(*
Token);
292 ShouldAddTarget = ShouldAddTarget && !TokenRef.starts_with(TargetOPT) &&
293 TokenRef != TargetOPTLegacy;
294 ShouldAddMode = ShouldAddMode && !TokenRef.starts_with(DriverModeOPT);
297 CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
299 if (ShouldAddTarget) {
300 CommandLine.insert(++CommandLine.begin(),
301 (TargetOPT + TargetMode.TargetPrefix).str());
306 llvm::StringRef WorkingDir,
307 llvm::cl::TokenizerCallback Tokenizer,
308 llvm::vfs::FileSystem &FS) {
309 bool SeenRSPFile =
false;
311 Argv.reserve(CommandLine.size());
312 for (
auto &Arg : CommandLine) {
313 Argv.push_back(Arg.c_str());
315 SeenRSPFile |= Arg.front() ==
'@';
319 llvm::BumpPtrAllocator Alloc;
320 llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
322 ECtx.setVFS(&FS).setCurrentDir(WorkingDir).expandResponseFiles(Argv);
326 std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
327 CommandLine = std::move(ExpandedArgv);
336 std::unique_ptr<FrontendAction> Action;
339 SingleFrontendActionFactory(std::unique_ptr<FrontendAction> Action)
340 : Action(std::move(Action)) {}
342 std::unique_ptr<FrontendAction>
create()
override {
343 return std::move(Action);
350 std::vector<std::string> CommandLine,
ToolAction *Action,
351 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
352 : CommandLine(
std::move(CommandLine)), Action(Action), OwnsAction(
false),
353 Files(Files), PCHContainerOps(
std::move(PCHContainerOps)) {}
356 std::vector<std::string> CommandLine,
357 std::unique_ptr<FrontendAction> FAction,
FileManager *Files,
358 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
359 : CommandLine(
std::move(CommandLine)),
360 Action(new SingleFrontendActionFactory(
std::move(FAction))),
361 OwnsAction(
true), Files(Files),
362 PCHContainerOps(
std::move(PCHContainerOps)) {}
370 llvm::opt::ArgStringList Argv;
371 for (
const std::string &Str : CommandLine)
372 Argv.push_back(Str.c_str());
373 const char *
const BinaryName = Argv[0];
377 std::unique_ptr<DiagnosticOptions> ParsedDiagOpts;
381 DiagOpts = &*ParsedDiagOpts;
387 Files->getVirtualFileSystem(), *DiagOpts,
388 DiagConsumer ? DiagConsumer : &DiagnosticPrinter,
false);
392 Diagnostics->setSourceManager(&
SrcMgr);
395 if (CommandLine.size() >= 2 && CommandLine[1] ==
"-cc1") {
397 std::unique_ptr<CompilerInvocation> Invocation(
399 if (Diagnostics->hasErrorOccurred())
401 return Action->runInvocation(std::move(Invocation), Files,
402 std::move(PCHContainerOps), DiagConsumer);
405 const std::unique_ptr<driver::Driver> Driver(
406 newDriver(&*Diagnostics, BinaryName, Files->getVirtualFileSystemPtr()));
411 if (!Files->getFileSystemOpts().WorkingDir.empty())
412 Driver->setCheckInputsExist(
false);
413 const std::unique_ptr<driver::Compilation> Compilation(
418 &*Diagnostics, Compilation.get());
421 std::unique_ptr<CompilerInvocation> Invocation(
423 return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
424 std::move(PCHContainerOps));
427bool ToolInvocation::runInvocation(
429 std::shared_ptr<CompilerInvocation> Invocation,
430 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
432 if (Invocation->getHeaderSearchOpts().Verbose) {
433 llvm::errs() <<
"clang Invocation:\n";
435 llvm::errs() <<
"\n";
439 std::move(PCHContainerOps), DiagConsumer);
443 std::shared_ptr<CompilerInvocation> Invocation,
FileManager *Files,
444 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
447 CompilerInstance Compiler(std::move(Invocation), std::move(PCHContainerOps));
454 std::unique_ptr<FrontendAction> ScopedToolAction(
create());
471 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
474 : Compilations(Compilations), SourcePaths(SourcePaths),
475 PCHContainerOps(
std::move(PCHContainerOps)),
476 OverlayFileSystem(
llvm::makeIntrusiveRefCnt<
llvm::
vfs::OverlayFileSystem>(
479 llvm::makeIntrusiveRefCnt<
llvm::
vfs::InMemoryFileSystem>()),
482 OverlayFileSystem)) {
483 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
488 Files->setVirtualFileSystem(OverlayFileSystem);
494 MappedFileContents.push_back(std::make_pair(FilePath, Content));
498 ArgsAdjuster =
combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
502 ArgsAdjuster =
nullptr;
508 for (StringRef Arg : Args)
509 if (Arg.starts_with(
"-resource-dir"))
520 static int StaticSymbol;
524 if (SeenWorkingDirectories.insert(
"/").second)
525 for (
const auto &MappedFile : MappedFileContents)
526 if (llvm::sys::path::is_absolute(MappedFile.first))
527 InMemoryFileSystem->addFile(
529 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
531 bool ProcessingFailed =
false;
532 bool FileSkipped =
false;
535 std::vector<std::string> AbsolutePaths;
536 AbsolutePaths.reserve(SourcePaths.size());
537 for (
const auto &SourcePath : SourcePaths) {
540 llvm::errs() <<
"Skipping " << SourcePath
541 <<
". Error while getting an absolute path: "
542 << llvm::toString(AbsPath.takeError()) <<
"\n";
545 AbsolutePaths.push_back(std::move(*AbsPath));
549 std::string InitialWorkingDir;
550 if (
auto CWD = OverlayFileSystem->getCurrentWorkingDirectory()) {
551 InitialWorkingDir = std::move(*CWD);
553 llvm::errs() <<
"Could not get working directory: "
554 << CWD.getError().message() <<
"\n";
557 size_t NumOfTotalFiles = AbsolutePaths.size();
558 unsigned ProcessedFileCounter = 0;
559 for (llvm::StringRef
File : AbsolutePaths) {
567 std::vector<CompileCommand> CompileCommandsForFile =
568 Compilations.getCompileCommands(
File);
569 if (CompileCommandsForFile.empty()) {
570 llvm::errs() <<
"Skipping " <<
File <<
". Compile command not found.\n";
578 if (Directory.empty()) {
579 llvm::errs() <<
"'directory' field of compilation database is empty; "
580 "using the current working directory instead.\n";
581 Directory = InitialWorkingDir;
591 if (OverlayFileSystem->setCurrentWorkingDirectory(Directory))
592 llvm::report_fatal_error(
"Cannot chdir into \"" + Twine(Directory) +
598 if (SeenWorkingDirectories.insert(Directory).second)
599 for (
const auto &MappedFile : MappedFileContents)
600 if (!llvm::sys::path::is_absolute(MappedFile.first))
601 InMemoryFileSystem->addFile(
603 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
608 assert(!CommandLine.empty());
622 if (NumOfTotalFiles > 1)
623 llvm::errs() <<
"[" + std::to_string(++ProcessedFileCounter) +
"/" +
624 std::to_string(NumOfTotalFiles) +
625 "] Processing file " +
File
627 ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
631 if (!Invocation.
run()) {
633 if (PrintErrorMessage)
634 llvm::errs() <<
"Error while processing " <<
File <<
".\n";
635 ProcessingFailed =
true;
640 if (!InitialWorkingDir.empty()) {
642 OverlayFileSystem->setCurrentWorkingDirectory(InitialWorkingDir))
643 llvm::errs() <<
"Error when trying to restore working dir: "
644 << EC.message() <<
"\n";
646 return ProcessingFailed ? 1 : (FileSkipped ? 2 : 0);
652 std::vector<std::unique_ptr<ASTUnit>> &ASTs;
657 std::vector<std::unique_ptr<ASTUnit>> &ASTs,
659 : ASTs(ASTs), CaptureKind(CaptureDiagnosticsKind) {}
661 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
663 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
665 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
666 Invocation, std::move(PCHContainerOps),
nullptr,
668 Invocation->getDiagnosticOpts(),
671 Files,
false, CaptureKind);
675 ASTs.push_back(std::move(AST));
683 ASTBuilderAction Action(ASTs);
688 this->PrintErrorMessage = PrintErrorMessage;
694std::unique_ptr<ASTUnit>
696 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
698 "clang-tool", std::move(PCHContainerOps));
702 StringRef Code,
const std::vector<std::string> &Args, StringRef
FileName,
703 StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps,
708 std::vector<std::unique_ptr<ASTUnit>> ASTs;
710 ASTBuilderAction Action(ASTs, CaptureKind);
712 auto OverlayFileSystem =
713 llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
715 auto InMemoryFileSystem =
716 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
717 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
724 &Action, Files.get(), std::move(PCHContainerOps));
727 InMemoryFileSystem->addFile(
FileName, 0,
728 llvm::MemoryBuffer::getMemBufferCopy(Code));
729 for (
auto &FilenameWithContent : VirtualMappedFiles) {
730 InMemoryFileSystem->addFile(
731 FilenameWithContent.first, 0,
732 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
735 if (!Invocation.
run())
738 assert(ASTs.size() == 1);
739 return std::move(ASTs[0]);
Defines the Diagnostic-related interfaces.
Defines the Diagnostic IDs-related interfaces.
Defines the clang::FileManager interface and associated types.
Defines the clang::FileSystemOptions interface.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
void setVirtualFileSystem(IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
Use the given file system.
bool hasDiagnostics() const
void createSourceManager()
Create the source manager and replace any existing one with it.
void setFileManager(IntrusiveRefCntPtr< FileManager > Value)
Replace the current file manager.
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
Helper class for holding the data necessary to invoke the compiler.
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
FrontendOptions & getFrontendOpts()
CodeGenOptions & getCodeGenOpts()
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Implements support for file system lookup, file system caching, and directory search management.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
llvm::vfs::FileSystem & getVirtualFileSystem() const
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
Keeps track of options that affect how file operations are performed.
unsigned DisableFree
Disable memory freeing on exit.
This class handles loading and caching of source files into memory.
Token - This structure provides full information about a lexed token.
Command - An executable path/name and argument vector to execute.
Compilation - A set of tasks to perform for a single driver invocation.
ActionList & getActions()
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
void setTitle(std::string Value)
JobList - A sequence of jobs to perform.
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Public enums and private classes that are part of the SourceManager implementation.
SmallVector< Action *, 3 > ActionList
ActionList - Type used for lists of actions.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions &DiagOpts, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
CaptureDiagsKind
Enumerates the available kinds for capturing diagnostics.
std::string GetResourcesPath(StringRef BinaryPath)
Get the directory where the compiler headers reside, relative to the compiler binary path BinaryPath.
const llvm::opt::OptTable & getDriverOptTable()
Diagnostic wrappers for TextAPI types for error reporting.