27 #include "llvm/ADT/STLExtras.h"
28 #include "llvm/Config/llvm-config.h"
29 #include "llvm/Option/Option.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/Host.h"
33 #include "llvm/Support/raw_ostream.h"
35 #define DEBUG_TYPE "clang-tooling"
53 BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics, VFS);
54 CompilerDriver->
setTitle(
"clang_based_tool");
55 return CompilerDriver;
67 if (Jobs.
size() != 1 || !isa<clang::driver::Command>(*Jobs.
begin())) {
69 llvm::raw_svector_ostream error_stream(error_msg);
70 Jobs.
Print(error_stream,
"; ",
true);
71 Diagnostics->
Report(clang::diag::err_fe_expected_compiler_job)
72 << error_stream.str();
78 cast<clang::driver::Command>(*Jobs.
begin());
80 Diagnostics->
Report(clang::diag::err_fe_expected_clang_command);
90 const llvm::opt::ArgStringList &CC1Args) {
91 assert(!CC1Args.empty() &&
"Must at least contain the program name!");
94 *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
96 Invocation->getFrontendOpts().DisableFree =
false;
97 Invocation->getCodeGenOpts().DisableFree =
false;
103 const Twine &FileName,
104 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
106 FileName, PCHContainerOps);
109 static std::vector<std::string>
111 StringRef FileName) {
112 std::vector<std::string> Args;
113 Args.push_back(
"clang-tool");
114 Args.push_back(
"-fsyntax-only");
115 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
116 Args.push_back(FileName.str());
122 const std::vector<std::string> &Args,
const Twine &FileName,
123 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
127 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
132 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
136 ToolAction, Files.get(), PCHContainerOps);
139 InMemoryFileSystem->addFile(FileNameRef, 0,
140 llvm::MemoryBuffer::getMemBuffer(
141 Code.toNullTerminatedStringRef(CodeStorage)));
143 for (
auto &FilenameWithContent : VirtualMappedFiles) {
144 InMemoryFileSystem->addFile(
145 FilenameWithContent.first, 0,
146 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
149 return Invocation.run();
153 StringRef RelativePath(File);
155 if (RelativePath.startswith(
"./")) {
156 RelativePath = RelativePath.substr(strlen(
"./"));
160 std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
163 llvm::sys::path::native(AbsolutePath);
164 return AbsolutePath.str();
168 StringRef InvokedAs) {
169 if (!CommandLine.empty() && !InvokedAs.empty()) {
170 bool AlreadyHasTarget =
false;
171 bool AlreadyHasMode =
false;
173 for (
auto Token = ++CommandLine.begin();
Token != CommandLine.end();
175 StringRef TokenRef(*
Token);
177 (TokenRef ==
"-target" || TokenRef.startswith(
"-target="));
178 AlreadyHasMode |= (TokenRef ==
"--driver-mode" ||
179 TokenRef.startswith(
"--driver-mode="));
183 if (!AlreadyHasMode && !TargetMode.second.empty()) {
184 CommandLine.insert(++CommandLine.begin(), TargetMode.second);
186 if (!AlreadyHasTarget && !TargetMode.first.empty()) {
187 CommandLine.insert(++CommandLine.begin(), {
"-target", TargetMode.first});
194 class SingleFrontendActionFactory :
public FrontendActionFactory {
198 SingleFrontendActionFactory(FrontendAction *
Action) : Action(Action) {}
207 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
208 : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(
false),
209 Files(Files), PCHContainerOps(PCHContainerOps), DiagConsumer(nullptr) {}
213 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
214 : CommandLine(std::move(CommandLine)),
215 Action(new SingleFrontendActionFactory(FAction)), OwnsAction(
true),
216 Files(Files), PCHContainerOps(PCHContainerOps), DiagConsumer(nullptr) {}
225 llvm::sys::path::native(FilePath, PathStorage);
226 MappedFileContents[PathStorage] = Content;
230 std::vector<const char*> Argv;
231 for (
const std::string &Str : CommandLine)
232 Argv.push_back(Str.c_str());
233 const char *
const BinaryName = Argv[0];
236 llvm::errs(), &*DiagOpts);
239 DiagConsumer ? DiagConsumer : &DiagnosticPrinter,
false);
241 const std::unique_ptr<clang::driver::Driver> Driver(
244 Driver->setCheckInputsExist(
false);
245 const std::unique_ptr<clang::driver::Compilation> Compilation(
246 Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
248 &Diagnostics, Compilation.get());
252 std::unique_ptr<clang::CompilerInvocation> Invocation(
255 for (
const auto &It : MappedFileContents) {
257 std::unique_ptr<llvm::MemoryBuffer>
Input =
258 llvm::MemoryBuffer::getMemBuffer(It.getValue());
259 Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
262 return runInvocation(BinaryName, Compilation.get(), Invocation.release(),
266 bool ToolInvocation::runInvocation(
269 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
272 llvm::errs() <<
"clang Invocation:\n";
274 llvm::errs() <<
"\n";
277 return Action->
runInvocation(Invocation, Files, PCHContainerOps,
283 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
293 std::unique_ptr<FrontendAction> ScopedToolAction(
create());
302 const bool Success = Compiler.
ExecuteAction(*ScopedToolAction);
310 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
311 : Compilations(Compilations), SourcePaths(SourcePaths),
312 PCHContainerOps(PCHContainerOps),
314 InMemoryFileSystem(new vfs::InMemoryFileSystem),
316 DiagConsumer(nullptr) {
317 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
325 MappedFileContents.push_back(std::make_pair(FilePath, Content));
332 ArgsAdjuster = Adjuster;
336 ArgsAdjuster =
nullptr;
342 static int StaticSymbol;
348 std::string MainExecutable =
349 llvm::sys::fs::getMainExecutable(
"clang_tool", &StaticSymbol);
352 if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
353 llvm::report_fatal_error(
"Cannot detect current path: " +
354 Twine(EC.message()));
358 if (SeenWorkingDirectories.insert(
"/").second)
359 for (
const auto &MappedFile : MappedFileContents)
360 if (llvm::sys::path::is_absolute(MappedFile.first))
361 InMemoryFileSystem->addFile(
363 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
365 bool ProcessingFailed =
false;
366 for (
const auto &SourcePath : SourcePaths) {
376 std::vector<CompileCommand> CompileCommandsForFile =
378 if (CompileCommandsForFile.empty()) {
384 llvm::errs() <<
"Skipping " << File <<
". Compile command not found.\n";
395 if (OverlayFileSystem->setCurrentWorkingDirectory(
397 llvm::report_fatal_error(
"Cannot chdir into \"" +
404 for (
const auto &MappedFile : MappedFileContents)
405 if (!llvm::sys::path::is_absolute(MappedFile.first))
406 InMemoryFileSystem->addFile(
408 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
413 assert(!CommandLine.empty());
414 CommandLine[0] = MainExecutable;
417 DEBUG({ llvm::dbgs() <<
"Processing: " << File <<
".\n"; });
418 ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
420 Invocation.setDiagnosticConsumer(DiagConsumer);
422 if (!Invocation.run()) {
424 llvm::errs() <<
"Error while processing " << File <<
".\n";
425 ProcessingFailed =
true;
429 if (OverlayFileSystem->setCurrentWorkingDirectory(InitialDirectory.c_str()))
430 llvm::report_fatal_error(
"Cannot chdir into \"" +
431 Twine(InitialDirectory) +
"\n!");
434 return ProcessingFailed ? 1 : 0;
440 std::vector<std::unique_ptr<ASTUnit>> &
ASTs;
443 ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &
ASTs) :
ASTs(
ASTs) {}
445 bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
446 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
447 DiagnosticConsumer *DiagConsumer)
override {
448 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
449 Invocation, PCHContainerOps,
457 ASTs.push_back(std::move(AST));
469 std::unique_ptr<ASTUnit>
471 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
477 const Twine &Code,
const std::vector<std::string> &Args,
478 const Twine &FileName,
479 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
481 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
483 std::vector<std::unique_ptr<ASTUnit>>
ASTs;
484 ASTBuilderAction
Action(ASTs);
489 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
493 Files.get(), PCHContainerOps);
496 InMemoryFileSystem->addFile(FileNameRef, 0,
497 llvm::MemoryBuffer::getMemBuffer(
498 Code.toNullTerminatedStringRef(CodeStorage)));
499 if (!Invocation.run())
502 assert(ASTs.size() == 1);
503 return std::move(ASTs[0]);
HeaderSearchOptions & getHeaderSearchOpts()
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.
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
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.
IntrusiveRefCntPtr< vfs::FileSystem > getVirtualFileSystem() const
Concrete class used by the front-end to report problems and issues.
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.
void setInvocation(CompilerInvocation *Value)
setInvocation - Replace the current invocation.
bool hasDiagnostics() const
JobList - A sequence of jobs to perform.
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.
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
void setTitle(std::string Value)
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.
std::vector< std::string > CommandLine
Compilation - A set of tasks to perform for a single driver invocation.
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Keeps track of options that affect how file operations are performed.