28 #include "llvm/ADT/STLExtras.h" 29 #include "llvm/Config/llvm-config.h" 30 #include "llvm/Option/ArgList.h" 31 #include "llvm/Option/Option.h" 32 #include "llvm/Support/CommandLine.h" 33 #include "llvm/Support/Debug.h" 34 #include "llvm/Support/FileSystem.h" 35 #include "llvm/Support/Host.h" 36 #include "llvm/Support/Path.h" 37 #include "llvm/Support/raw_ostream.h" 40 #define DEBUG_TYPE "clang-tooling" 59 *Diagnostics, std::move(VFS));
60 CompilerDriver->
setTitle(
"clang_based_tool");
61 return CompilerDriver;
73 if (Jobs.
size() != 1 || !isa<clang::driver::Command>(*Jobs.
begin())) {
75 llvm::raw_svector_ostream error_stream(error_msg);
76 Jobs.
Print(error_stream,
"; ",
true);
77 Diagnostics->
Report(clang::diag::err_fe_expected_compiler_job)
78 << error_stream.str();
84 cast<clang::driver::Command>(*Jobs.
begin());
86 Diagnostics->
Report(clang::diag::err_fe_expected_clang_command);
96 const llvm::opt::ArgStringList &CC1Args) {
97 assert(!CC1Args.empty() &&
"Must at least contain the program name!");
100 *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
102 Invocation->getFrontendOpts().DisableFree =
false;
103 Invocation->getCodeGenOpts().DisableFree =
false;
108 const Twine &FileName,
109 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
111 FileName,
"clang-tool",
112 std::move(PCHContainerOps));
115 static std::vector<std::string>
117 const std::vector<std::string> &ExtraArgs,
118 StringRef FileName) {
119 std::vector<std::string> Args;
120 Args.push_back(ToolName.str());
121 Args.push_back(
"-fsyntax-only");
122 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
123 Args.push_back(FileName.str());
129 const std::vector<std::string> &Args,
const Twine &FileName,
130 const Twine &ToolName,
131 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
135 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
140 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
146 ToolAction, Files.get(),
147 std::move(PCHContainerOps));
150 InMemoryFileSystem->addFile(FileNameRef, 0,
151 llvm::MemoryBuffer::getMemBuffer(
152 Code.toNullTerminatedStringRef(CodeStorage)));
154 for (
auto &FilenameWithContent : VirtualMappedFiles) {
155 InMemoryFileSystem->addFile(
156 FilenameWithContent.first, 0,
157 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
160 return Invocation.run();
164 StringRef RelativePath(File);
166 if (RelativePath.startswith(
"./")) {
167 RelativePath = RelativePath.substr(strlen(
"./"));
171 std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
174 llvm::sys::path::native(AbsolutePath);
175 return AbsolutePath.str();
179 StringRef InvokedAs) {
180 if (!CommandLine.empty() && !InvokedAs.empty()) {
181 bool AlreadyHasTarget =
false;
182 bool AlreadyHasMode =
false;
184 for (
auto Token = ++CommandLine.begin();
Token != CommandLine.end();
186 StringRef TokenRef(*
Token);
188 (TokenRef ==
"-target" || TokenRef.startswith(
"-target="));
189 AlreadyHasMode |= (TokenRef ==
"--driver-mode" ||
190 TokenRef.startswith(
"--driver-mode="));
194 if (!AlreadyHasMode && TargetMode.DriverMode) {
195 CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
197 if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
198 CommandLine.insert(++CommandLine.begin(), {
"-target",
199 TargetMode.TargetPrefix});
210 SingleFrontendActionFactory(
FrontendAction *Action) : Action(Action) {}
218 std::vector<std::string> CommandLine,
ToolAction *Action,
219 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
220 : CommandLine(
std::move(CommandLine)), Action(Action), OwnsAction(
false),
221 Files(Files), PCHContainerOps(
std::move(PCHContainerOps)),
222 DiagConsumer(nullptr) {}
226 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
227 : CommandLine(
std::move(CommandLine)),
228 Action(new SingleFrontendActionFactory(FAction)), OwnsAction(
true),
229 Files(Files), PCHContainerOps(
std::move(PCHContainerOps)),
230 DiagConsumer(nullptr) {}
239 llvm::sys::path::native(FilePath, PathStorage);
240 MappedFileContents[PathStorage] = Content;
244 std::vector<const char*> Argv;
245 for (
const std::string &Str : CommandLine)
246 Argv.push_back(Str.c_str());
247 const char *
const BinaryName = Argv[0];
249 unsigned MissingArgIndex, MissingArgCount;
251 llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs(
255 llvm::errs(), &*DiagOpts);
258 DiagConsumer ? DiagConsumer : &DiagnosticPrinter,
false);
260 const std::unique_ptr<clang::driver::Driver> Driver(
263 Driver->setCheckInputsExist(
false);
264 const std::unique_ptr<clang::driver::Compilation> Compilation(
265 Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
269 &Diagnostics, Compilation.get());
273 std::unique_ptr<clang::CompilerInvocation> Invocation(
276 for (
const auto &It : MappedFileContents) {
278 std::unique_ptr<llvm::MemoryBuffer> Input =
279 llvm::MemoryBuffer::getMemBuffer(It.getValue());
280 Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
283 return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
284 std::move(PCHContainerOps));
287 bool ToolInvocation::runInvocation(
289 std::shared_ptr<clang::CompilerInvocation> Invocation,
290 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
292 if (Invocation->getHeaderSearchOpts().Verbose) {
293 llvm::errs() <<
"clang Invocation:\n";
295 llvm::errs() <<
"\n";
299 std::move(PCHContainerOps), DiagConsumer);
303 std::shared_ptr<CompilerInvocation> Invocation,
FileManager *Files,
304 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
314 std::unique_ptr<FrontendAction> ScopedToolAction(
create());
323 const bool Success = Compiler.
ExecuteAction(*ScopedToolAction);
331 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
332 : Compilations(Compilations), SourcePaths(SourcePaths),
333 PCHContainerOps(
std::move(PCHContainerOps)),
335 InMemoryFileSystem(new vfs::InMemoryFileSystem),
337 DiagConsumer(nullptr) {
338 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
347 MappedFileContents.push_back(std::make_pair(FilePath, Content));
351 ArgsAdjuster =
combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
355 ArgsAdjuster =
nullptr;
361 for (StringRef Arg : Args)
362 if (Arg.startswith(
"-resource-dir"))
366 Args.push_back(
"-resource-dir=" +
373 static int StaticSymbol;
376 if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
377 llvm::report_fatal_error(
"Cannot detect current path: " +
378 Twine(EC.message()));
382 if (SeenWorkingDirectories.insert(
"/").second)
383 for (
const auto &MappedFile : MappedFileContents)
384 if (llvm::sys::path::is_absolute(MappedFile.first))
385 InMemoryFileSystem->addFile(
387 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
389 bool ProcessingFailed =
false;
390 for (
const auto &SourcePath : SourcePaths) {
400 std::vector<CompileCommand> CompileCommandsForFile =
402 if (CompileCommandsForFile.empty()) {
408 llvm::errs() <<
"Skipping " << File <<
". Compile command not found.\n";
419 if (OverlayFileSystem->setCurrentWorkingDirectory(
421 llvm::report_fatal_error(
"Cannot chdir into \"" +
428 for (
const auto &MappedFile : MappedFileContents)
429 if (!llvm::sys::path::is_absolute(MappedFile.first))
430 InMemoryFileSystem->addFile(
432 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
437 assert(!CommandLine.empty());
451 DEBUG({ llvm::dbgs() <<
"Processing: " << File <<
".\n"; });
452 ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
456 if (!Invocation.run()) {
458 llvm::errs() <<
"Error while processing " << File <<
".\n";
459 ProcessingFailed =
true;
463 if (OverlayFileSystem->setCurrentWorkingDirectory(InitialDirectory.c_str()))
464 llvm::report_fatal_error(
"Cannot chdir into \"" +
465 Twine(InitialDirectory) +
"\n!");
468 return ProcessingFailed ? 1 : 0;
474 std::vector<std::unique_ptr<ASTUnit>> &ASTs;
477 ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
479 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
481 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
483 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
484 Invocation, std::move(PCHContainerOps),
492 ASTs.push_back(std::move(AST));
499 ASTBuilderAction Action(ASTs);
503 std::unique_ptr<ASTUnit>
505 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
507 "clang-tool", std::move(PCHContainerOps));
511 const Twine &Code,
const std::vector<std::string> &Args,
512 const Twine &FileName,
const Twine &ToolName,
513 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
516 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
518 std::vector<std::unique_ptr<ASTUnit>> ASTs;
519 ASTBuilderAction Action(ASTs);
524 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
530 &Action, Files.get(), std::move(PCHContainerOps));
533 InMemoryFileSystem->addFile(FileNameRef, 0,
534 llvm::MemoryBuffer::getMemBuffer(
535 Code.toNullTerminatedStringRef(CodeStorage)));
536 if (!Invocation.run())
539 assert(ASTs.size() == 1);
540 return std::move(ASTs[0]);
bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, DiagnosticsEngine *Diags=nullptr, bool DefaultDiagColor=true, bool DefaultShowOpt=true)
Fill out Opts based on the options given in Args.
Implements support for file system lookup, file system caching, and directory search management...
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation's diagnostic options and replace any existing one ...
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
Abstract base class for actions which can be performed by the frontend.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
static bool CreateFromArgs(CompilerInvocation &Res, const char *const *ArgBegin, const char *const *ArgEnd, DiagnosticsEngine &Diags)
Create a compiler invocation from a list of input options.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
void createSourceManager(FileManager &FileMgr)
Create the source manager and replace any existing one with it.
Token - This structure provides full information about a lexed token.
An in-memory file system.
A file system that allows overlaying one AbstractFileSystem on top of another.
Concrete class used by the front-end to report problems and issues.
std::unique_ptr< llvm::opt::OptTable > createDriverOptTable()
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
static std::string GetResourcesPath(const char *Argv0, void *MainAddr)
Get the directory where the compiler headers reside, relative to the compiler binary (found by the pa...
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
JobList - A sequence of jobs to perform.
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Options for controlling the compiler diagnostics engine.
Command - An executable path/name and argument vector to execute.
void clearStatCaches()
Removes all FileSystemStatCache objects from the manager.
void setTitle(std::string Value)
Dataflow Directional Tag Classes.
const llvm::opt::ArgStringList & getArguments() const
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
Used for handling and querying diagnostic IDs.
Helper class for holding the data necessary to invoke the compiler.
Compilation - A set of tasks to perform for a single driver invocation.
bool hasDiagnostics() const
Keeps track of options that affect how file operations are performed.
void setInvocation(std::shared_ptr< CompilerInvocation > Value)
setInvocation - Replace the current invocation.
IntrusiveRefCntPtr< vfs::FileSystem > getVirtualFileSystem() const