26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/Config/llvm-config.h"
28 #include "llvm/Option/Option.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/Host.h"
32 #include "llvm/Support/raw_ostream.h"
41 #define DEBUG_TYPE "clang-tooling"
56 const char *BinaryName) {
58 BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics);
59 CompilerDriver->
setTitle(
"clang_based_tool");
60 return CompilerDriver;
72 if (Jobs.
size() != 1 || !isa<clang::driver::Command>(*Jobs.
begin())) {
74 llvm::raw_svector_ostream error_stream(error_msg);
75 Jobs.
Print(error_stream,
"; ",
true);
76 Diagnostics->
Report(clang::diag::err_fe_expected_compiler_job)
77 << error_stream.str();
83 cast<clang::driver::Command>(*Jobs.
begin());
85 Diagnostics->
Report(clang::diag::err_fe_expected_clang_command);
95 const llvm::opt::ArgStringList &CC1Args) {
96 assert(!CC1Args.empty() &&
"Must at least contain the program name!");
99 *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
101 Invocation->getFrontendOpts().DisableFree =
false;
102 Invocation->getCodeGenOpts().DisableFree =
false;
108 const Twine &FileName,
109 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
111 FileName, PCHContainerOps);
114 static std::vector<std::string>
116 StringRef FileName) {
117 std::vector<std::string> Args;
118 Args.push_back(
"clang-tool");
119 Args.push_back(
"-fsyntax-only");
120 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
121 Args.push_back(FileName.str());
127 const std::vector<std::string> &Args,
const Twine &FileName,
128 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
132 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
136 ToolAction, Files.get(), PCHContainerOps);
139 Invocation.mapVirtualFile(FileNameRef,
140 Code.toNullTerminatedStringRef(CodeStorage));
142 for (
auto &FilenameWithContent : VirtualMappedFiles) {
143 Invocation.mapVirtualFile(FilenameWithContent.first,
144 FilenameWithContent.second);
147 return Invocation.run();
151 StringRef RelativePath(File);
153 if (RelativePath.startswith(
"./")) {
154 RelativePath = RelativePath.substr(strlen(
"./"));
158 std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
161 llvm::sys::path::native(AbsolutePath);
162 return AbsolutePath.str();
167 class SingleFrontendActionFactory :
public FrontendActionFactory {
171 SingleFrontendActionFactory(FrontendAction *
Action) : Action(Action) {}
180 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
181 : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(
false),
182 Files(Files), PCHContainerOps(PCHContainerOps), DiagConsumer(nullptr) {}
186 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
187 : CommandLine(std::move(CommandLine)),
188 Action(new SingleFrontendActionFactory(FAction)), OwnsAction(
true),
189 Files(Files), PCHContainerOps(PCHContainerOps), DiagConsumer(nullptr) {}
198 llvm::sys::path::native(FilePath, PathStorage);
199 MappedFileContents[PathStorage] = Content;
203 std::vector<const char*> Argv;
204 for (
const std::string &Str : CommandLine)
205 Argv.push_back(Str.c_str());
206 const char *
const BinaryName = Argv[0];
209 llvm::errs(), &*DiagOpts);
212 DiagConsumer ? DiagConsumer : &DiagnosticPrinter,
false);
214 const std::unique_ptr<clang::driver::Driver> Driver(
217 Driver->setCheckInputsExist(
false);
218 const std::unique_ptr<clang::driver::Compilation> Compilation(
219 Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
221 &Diagnostics, Compilation.get());
225 std::unique_ptr<clang::CompilerInvocation> Invocation(
227 for (
const auto &It : MappedFileContents) {
229 std::unique_ptr<llvm::MemoryBuffer>
Input =
230 llvm::MemoryBuffer::getMemBuffer(It.getValue());
231 Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
234 return runInvocation(BinaryName, Compilation.get(), Invocation.release(),
238 bool ToolInvocation::runInvocation(
241 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
244 llvm::errs() <<
"clang Invocation:\n";
246 llvm::errs() <<
"\n";
249 return Action->
runInvocation(Invocation, Files, PCHContainerOps,
255 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
265 std::unique_ptr<FrontendAction> ScopedToolAction(
create());
274 const bool Success = Compiler.
ExecuteAction(*ScopedToolAction);
282 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
283 : Compilations(Compilations), SourcePaths(SourcePaths),
284 PCHContainerOps(PCHContainerOps),
293 MappedFileContents.push_back(std::make_pair(FilePath, Content));
300 ArgsAdjuster = Adjuster;
304 ArgsAdjuster =
nullptr;
310 static int StaticSymbol;
316 std::string MainExecutable =
317 llvm::sys::fs::getMainExecutable(
"clang_tool", &StaticSymbol);
320 if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
321 llvm::report_fatal_error(
"Cannot detect current path: " +
322 Twine(EC.message()));
323 bool ProcessingFailed =
false;
324 for (
const auto &SourcePath : SourcePaths) {
334 std::vector<CompileCommand> CompileCommandsForFile =
336 if (CompileCommandsForFile.empty()) {
342 llvm::errs() <<
"Skipping " << File <<
". Compile command not found.\n";
354 llvm::report_fatal_error(
"Cannot chdir into \"" +
358 CommandLine = ArgsAdjuster(CommandLine);
359 assert(!CommandLine.empty());
360 CommandLine[0] = MainExecutable;
363 DEBUG({ llvm::dbgs() <<
"Processing: " << File <<
".\n"; });
364 ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
366 Invocation.setDiagnosticConsumer(DiagConsumer);
367 for (
const auto &MappedFile : MappedFileContents)
368 Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
369 if (!Invocation.run()) {
371 llvm::errs() <<
"Error while processing " << File <<
".\n";
372 ProcessingFailed =
true;
376 if (chdir(InitialDirectory.c_str()))
377 llvm::report_fatal_error(
"Cannot chdir into \"" +
378 Twine(InitialDirectory) +
"\n!");
381 return ProcessingFailed ? 1 : 0;
387 std::vector<std::unique_ptr<ASTUnit>> &
ASTs;
390 ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &
ASTs) :
ASTs(
ASTs) {}
392 bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
393 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
394 DiagnosticConsumer *DiagConsumer)
override {
396 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
397 Invocation, PCHContainerOps,
404 ASTs.push_back(std::move(AST));
416 std::unique_ptr<ASTUnit>
418 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
424 const Twine &Code,
const std::vector<std::string> &Args,
425 const Twine &FileName,
426 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
428 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
430 std::vector<std::unique_ptr<ASTUnit>>
ASTs;
431 ASTBuilderAction
Action(ASTs);
433 nullptr, PCHContainerOps);
437 Code.toNullTerminatedStringRef(CodeStorage));
438 if (!Invocation.
run())
441 assert(ASTs.size() == 1);
442 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)
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.
Concrete class used by the front-end to report problems and issues.
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)
Options for controlling the compiler diagnostics engine.
void clearStatCaches()
Removes all FileSystemStatCache objects from the manager.
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
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.