xref: /minix3/external/bsd/llvm/dist/clang/lib/Tooling/Tooling.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===--- Tooling.cpp - Running clang standalone tools ---------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc //  This file implements functions to run clang tools standalone instead
11f4a2713aSLionel Sambuc //  of running them as a plugin.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "clang/Tooling/Tooling.h"
16f4a2713aSLionel Sambuc #include "clang/AST/ASTConsumer.h"
17f4a2713aSLionel Sambuc #include "clang/Driver/Compilation.h"
18f4a2713aSLionel Sambuc #include "clang/Driver/Driver.h"
19f4a2713aSLionel Sambuc #include "clang/Driver/Tool.h"
20f4a2713aSLionel Sambuc #include "clang/Frontend/ASTUnit.h"
21f4a2713aSLionel Sambuc #include "clang/Frontend/CompilerInstance.h"
22f4a2713aSLionel Sambuc #include "clang/Frontend/FrontendDiagnostic.h"
23f4a2713aSLionel Sambuc #include "clang/Frontend/TextDiagnosticPrinter.h"
24f4a2713aSLionel Sambuc #include "clang/Tooling/ArgumentsAdjusters.h"
25f4a2713aSLionel Sambuc #include "clang/Tooling/CompilationDatabase.h"
26f4a2713aSLionel Sambuc #include "llvm/ADT/STLExtras.h"
27*0a6a1f1dSLionel Sambuc #include "llvm/Config/llvm-config.h"
28f4a2713aSLionel Sambuc #include "llvm/Option/Option.h"
29f4a2713aSLionel Sambuc #include "llvm/Support/Debug.h"
30f4a2713aSLionel Sambuc #include "llvm/Support/FileSystem.h"
31f4a2713aSLionel Sambuc #include "llvm/Support/Host.h"
32f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
33f4a2713aSLionel Sambuc 
34f4a2713aSLionel Sambuc // For chdir, see the comment in ClangTool::run for more information.
35*0a6a1f1dSLionel Sambuc #ifdef LLVM_ON_WIN32
36f4a2713aSLionel Sambuc #  include <direct.h>
37f4a2713aSLionel Sambuc #else
38f4a2713aSLionel Sambuc #  include <unistd.h>
39f4a2713aSLionel Sambuc #endif
40f4a2713aSLionel Sambuc 
41*0a6a1f1dSLionel Sambuc #define DEBUG_TYPE "clang-tooling"
42*0a6a1f1dSLionel Sambuc 
43f4a2713aSLionel Sambuc namespace clang {
44f4a2713aSLionel Sambuc namespace tooling {
45f4a2713aSLionel Sambuc 
~ToolAction()46f4a2713aSLionel Sambuc ToolAction::~ToolAction() {}
47f4a2713aSLionel Sambuc 
~FrontendActionFactory()48f4a2713aSLionel Sambuc FrontendActionFactory::~FrontendActionFactory() {}
49f4a2713aSLionel Sambuc 
50f4a2713aSLionel Sambuc // FIXME: This file contains structural duplication with other parts of the
51f4a2713aSLionel Sambuc // code that sets up a compiler to run tools on it, and we should refactor
52f4a2713aSLionel Sambuc // it to be based on the same framework.
53f4a2713aSLionel Sambuc 
54f4a2713aSLionel Sambuc /// \brief Builds a clang driver initialized for running clang tools.
newDriver(clang::DiagnosticsEngine * Diagnostics,const char * BinaryName)55f4a2713aSLionel Sambuc static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
56f4a2713aSLionel Sambuc                                         const char *BinaryName) {
57f4a2713aSLionel Sambuc   clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
58*0a6a1f1dSLionel Sambuc       BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics);
59f4a2713aSLionel Sambuc   CompilerDriver->setTitle("clang_based_tool");
60f4a2713aSLionel Sambuc   return CompilerDriver;
61f4a2713aSLionel Sambuc }
62f4a2713aSLionel Sambuc 
63f4a2713aSLionel Sambuc /// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
64f4a2713aSLionel Sambuc ///
65f4a2713aSLionel Sambuc /// Returns NULL on error.
getCC1Arguments(clang::DiagnosticsEngine * Diagnostics,clang::driver::Compilation * Compilation)66f4a2713aSLionel Sambuc static const llvm::opt::ArgStringList *getCC1Arguments(
67f4a2713aSLionel Sambuc     clang::DiagnosticsEngine *Diagnostics,
68f4a2713aSLionel Sambuc     clang::driver::Compilation *Compilation) {
69f4a2713aSLionel Sambuc   // We expect to get back exactly one Command job, if we didn't something
70f4a2713aSLionel Sambuc   // failed. Extract that job from the Compilation.
71f4a2713aSLionel Sambuc   const clang::driver::JobList &Jobs = Compilation->getJobs();
72f4a2713aSLionel Sambuc   if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
73f4a2713aSLionel Sambuc     SmallString<256> error_msg;
74f4a2713aSLionel Sambuc     llvm::raw_svector_ostream error_stream(error_msg);
75f4a2713aSLionel Sambuc     Jobs.Print(error_stream, "; ", true);
76f4a2713aSLionel Sambuc     Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
77f4a2713aSLionel Sambuc         << error_stream.str();
78*0a6a1f1dSLionel Sambuc     return nullptr;
79f4a2713aSLionel Sambuc   }
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc   // The one job we find should be to invoke clang again.
82*0a6a1f1dSLionel Sambuc   const clang::driver::Command &Cmd =
83f4a2713aSLionel Sambuc       cast<clang::driver::Command>(*Jobs.begin());
84*0a6a1f1dSLionel Sambuc   if (StringRef(Cmd.getCreator().getName()) != "clang") {
85f4a2713aSLionel Sambuc     Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
86*0a6a1f1dSLionel Sambuc     return nullptr;
87f4a2713aSLionel Sambuc   }
88f4a2713aSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc   return &Cmd.getArguments();
90f4a2713aSLionel Sambuc }
91f4a2713aSLionel Sambuc 
92f4a2713aSLionel Sambuc /// \brief Returns a clang build invocation initialized from the CC1 flags.
newInvocation(clang::DiagnosticsEngine * Diagnostics,const llvm::opt::ArgStringList & CC1Args)93f4a2713aSLionel Sambuc static clang::CompilerInvocation *newInvocation(
94f4a2713aSLionel Sambuc     clang::DiagnosticsEngine *Diagnostics,
95f4a2713aSLionel Sambuc     const llvm::opt::ArgStringList &CC1Args) {
96f4a2713aSLionel Sambuc   assert(!CC1Args.empty() && "Must at least contain the program name!");
97f4a2713aSLionel Sambuc   clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
98f4a2713aSLionel Sambuc   clang::CompilerInvocation::CreateFromArgs(
99f4a2713aSLionel Sambuc       *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
100f4a2713aSLionel Sambuc       *Diagnostics);
101f4a2713aSLionel Sambuc   Invocation->getFrontendOpts().DisableFree = false;
102f4a2713aSLionel Sambuc   Invocation->getCodeGenOpts().DisableFree = false;
103*0a6a1f1dSLionel Sambuc   Invocation->getDependencyOutputOpts() = DependencyOutputOptions();
104f4a2713aSLionel Sambuc   return Invocation;
105f4a2713aSLionel Sambuc }
106f4a2713aSLionel Sambuc 
runToolOnCode(clang::FrontendAction * ToolAction,const Twine & Code,const Twine & FileName)107f4a2713aSLionel Sambuc bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
108f4a2713aSLionel Sambuc                    const Twine &FileName) {
109f4a2713aSLionel Sambuc   return runToolOnCodeWithArgs(
110f4a2713aSLionel Sambuc       ToolAction, Code, std::vector<std::string>(), FileName);
111f4a2713aSLionel Sambuc }
112f4a2713aSLionel Sambuc 
113f4a2713aSLionel Sambuc static std::vector<std::string>
getSyntaxOnlyToolArgs(const std::vector<std::string> & ExtraArgs,StringRef FileName)114f4a2713aSLionel Sambuc getSyntaxOnlyToolArgs(const std::vector<std::string> &ExtraArgs,
115f4a2713aSLionel Sambuc                       StringRef FileName) {
116f4a2713aSLionel Sambuc   std::vector<std::string> Args;
117f4a2713aSLionel Sambuc   Args.push_back("clang-tool");
118f4a2713aSLionel Sambuc   Args.push_back("-fsyntax-only");
119f4a2713aSLionel Sambuc   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
120f4a2713aSLionel Sambuc   Args.push_back(FileName.str());
121f4a2713aSLionel Sambuc   return Args;
122f4a2713aSLionel Sambuc }
123f4a2713aSLionel Sambuc 
runToolOnCodeWithArgs(clang::FrontendAction * ToolAction,const Twine & Code,const std::vector<std::string> & Args,const Twine & FileName,const FileContentMappings & VirtualMappedFiles)124f4a2713aSLionel Sambuc bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
125f4a2713aSLionel Sambuc                            const std::vector<std::string> &Args,
126*0a6a1f1dSLionel Sambuc                            const Twine &FileName,
127*0a6a1f1dSLionel Sambuc                            const FileContentMappings &VirtualMappedFiles) {
128*0a6a1f1dSLionel Sambuc 
129f4a2713aSLionel Sambuc   SmallString<16> FileNameStorage;
130f4a2713aSLionel Sambuc   StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
131f4a2713aSLionel Sambuc   llvm::IntrusiveRefCntPtr<FileManager> Files(
132f4a2713aSLionel Sambuc       new FileManager(FileSystemOptions()));
133*0a6a1f1dSLionel Sambuc   ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef),
134*0a6a1f1dSLionel Sambuc                             ToolAction, Files.get());
135f4a2713aSLionel Sambuc 
136f4a2713aSLionel Sambuc   SmallString<1024> CodeStorage;
137f4a2713aSLionel Sambuc   Invocation.mapVirtualFile(FileNameRef,
138f4a2713aSLionel Sambuc                             Code.toNullTerminatedStringRef(CodeStorage));
139*0a6a1f1dSLionel Sambuc 
140*0a6a1f1dSLionel Sambuc   for (auto &FilenameWithContent : VirtualMappedFiles) {
141*0a6a1f1dSLionel Sambuc     Invocation.mapVirtualFile(FilenameWithContent.first,
142*0a6a1f1dSLionel Sambuc                               FilenameWithContent.second);
143*0a6a1f1dSLionel Sambuc   }
144*0a6a1f1dSLionel Sambuc 
145f4a2713aSLionel Sambuc   return Invocation.run();
146f4a2713aSLionel Sambuc }
147f4a2713aSLionel Sambuc 
getAbsolutePath(StringRef File)148f4a2713aSLionel Sambuc std::string getAbsolutePath(StringRef File) {
149f4a2713aSLionel Sambuc   StringRef RelativePath(File);
150f4a2713aSLionel Sambuc   // FIXME: Should '.\\' be accepted on Win32?
151f4a2713aSLionel Sambuc   if (RelativePath.startswith("./")) {
152f4a2713aSLionel Sambuc     RelativePath = RelativePath.substr(strlen("./"));
153f4a2713aSLionel Sambuc   }
154f4a2713aSLionel Sambuc 
155f4a2713aSLionel Sambuc   SmallString<1024> AbsolutePath = RelativePath;
156*0a6a1f1dSLionel Sambuc   std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
157f4a2713aSLionel Sambuc   assert(!EC);
158f4a2713aSLionel Sambuc   (void)EC;
159f4a2713aSLionel Sambuc   llvm::sys::path::native(AbsolutePath);
160f4a2713aSLionel Sambuc   return AbsolutePath.str();
161f4a2713aSLionel Sambuc }
162f4a2713aSLionel Sambuc 
163f4a2713aSLionel Sambuc namespace {
164f4a2713aSLionel Sambuc 
165f4a2713aSLionel Sambuc class SingleFrontendActionFactory : public FrontendActionFactory {
166f4a2713aSLionel Sambuc   FrontendAction *Action;
167f4a2713aSLionel Sambuc 
168f4a2713aSLionel Sambuc public:
SingleFrontendActionFactory(FrontendAction * Action)169f4a2713aSLionel Sambuc   SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}
170f4a2713aSLionel Sambuc 
create()171*0a6a1f1dSLionel Sambuc   FrontendAction *create() override { return Action; }
172f4a2713aSLionel Sambuc };
173f4a2713aSLionel Sambuc 
174f4a2713aSLionel Sambuc }
175f4a2713aSLionel Sambuc 
ToolInvocation(std::vector<std::string> CommandLine,ToolAction * Action,FileManager * Files)176*0a6a1f1dSLionel Sambuc ToolInvocation::ToolInvocation(std::vector<std::string> CommandLine,
177f4a2713aSLionel Sambuc                                ToolAction *Action, FileManager *Files)
178*0a6a1f1dSLionel Sambuc     : CommandLine(std::move(CommandLine)),
179f4a2713aSLionel Sambuc       Action(Action),
180f4a2713aSLionel Sambuc       OwnsAction(false),
181f4a2713aSLionel Sambuc       Files(Files),
182*0a6a1f1dSLionel Sambuc       DiagConsumer(nullptr) {}
183f4a2713aSLionel Sambuc 
ToolInvocation(std::vector<std::string> CommandLine,FrontendAction * FAction,FileManager * Files)184*0a6a1f1dSLionel Sambuc ToolInvocation::ToolInvocation(std::vector<std::string> CommandLine,
185f4a2713aSLionel Sambuc                                FrontendAction *FAction, FileManager *Files)
186*0a6a1f1dSLionel Sambuc     : CommandLine(std::move(CommandLine)),
187f4a2713aSLionel Sambuc       Action(new SingleFrontendActionFactory(FAction)),
188f4a2713aSLionel Sambuc       OwnsAction(true),
189f4a2713aSLionel Sambuc       Files(Files),
190*0a6a1f1dSLionel Sambuc       DiagConsumer(nullptr) {}
191f4a2713aSLionel Sambuc 
~ToolInvocation()192f4a2713aSLionel Sambuc ToolInvocation::~ToolInvocation() {
193f4a2713aSLionel Sambuc   if (OwnsAction)
194f4a2713aSLionel Sambuc     delete Action;
195f4a2713aSLionel Sambuc }
196f4a2713aSLionel Sambuc 
mapVirtualFile(StringRef FilePath,StringRef Content)197f4a2713aSLionel Sambuc void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
198f4a2713aSLionel Sambuc   SmallString<1024> PathStorage;
199f4a2713aSLionel Sambuc   llvm::sys::path::native(FilePath, PathStorage);
200f4a2713aSLionel Sambuc   MappedFileContents[PathStorage] = Content;
201f4a2713aSLionel Sambuc }
202f4a2713aSLionel Sambuc 
run()203f4a2713aSLionel Sambuc bool ToolInvocation::run() {
204f4a2713aSLionel Sambuc   std::vector<const char*> Argv;
205*0a6a1f1dSLionel Sambuc   for (const std::string &Str : CommandLine)
206*0a6a1f1dSLionel Sambuc     Argv.push_back(Str.c_str());
207f4a2713aSLionel Sambuc   const char *const BinaryName = Argv[0];
208f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
209f4a2713aSLionel Sambuc   TextDiagnosticPrinter DiagnosticPrinter(
210f4a2713aSLionel Sambuc       llvm::errs(), &*DiagOpts);
211f4a2713aSLionel Sambuc   DiagnosticsEngine Diagnostics(
212f4a2713aSLionel Sambuc       IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
213f4a2713aSLionel Sambuc       DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
214f4a2713aSLionel Sambuc 
215*0a6a1f1dSLionel Sambuc   const std::unique_ptr<clang::driver::Driver> Driver(
216f4a2713aSLionel Sambuc       newDriver(&Diagnostics, BinaryName));
217f4a2713aSLionel Sambuc   // Since the input might only be virtual, don't check whether it exists.
218f4a2713aSLionel Sambuc   Driver->setCheckInputsExist(false);
219*0a6a1f1dSLionel Sambuc   const std::unique_ptr<clang::driver::Compilation> Compilation(
220f4a2713aSLionel Sambuc       Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
221f4a2713aSLionel Sambuc   const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
222f4a2713aSLionel Sambuc       &Diagnostics, Compilation.get());
223*0a6a1f1dSLionel Sambuc   if (!CC1Args) {
224f4a2713aSLionel Sambuc     return false;
225f4a2713aSLionel Sambuc   }
226*0a6a1f1dSLionel Sambuc   std::unique_ptr<clang::CompilerInvocation> Invocation(
227f4a2713aSLionel Sambuc       newInvocation(&Diagnostics, *CC1Args));
228*0a6a1f1dSLionel Sambuc   for (const auto &It : MappedFileContents) {
229f4a2713aSLionel Sambuc     // Inject the code as the given file name into the preprocessor options.
230*0a6a1f1dSLionel Sambuc     std::unique_ptr<llvm::MemoryBuffer> Input =
231*0a6a1f1dSLionel Sambuc         llvm::MemoryBuffer::getMemBuffer(It.getValue());
232*0a6a1f1dSLionel Sambuc     Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
233*0a6a1f1dSLionel Sambuc                                                       Input.release());
234f4a2713aSLionel Sambuc   }
235*0a6a1f1dSLionel Sambuc   return runInvocation(BinaryName, Compilation.get(), Invocation.release());
236f4a2713aSLionel Sambuc }
237f4a2713aSLionel Sambuc 
runInvocation(const char * BinaryName,clang::driver::Compilation * Compilation,clang::CompilerInvocation * Invocation)238f4a2713aSLionel Sambuc bool ToolInvocation::runInvocation(
239f4a2713aSLionel Sambuc     const char *BinaryName,
240f4a2713aSLionel Sambuc     clang::driver::Compilation *Compilation,
241f4a2713aSLionel Sambuc     clang::CompilerInvocation *Invocation) {
242f4a2713aSLionel Sambuc   // Show the invocation, with -v.
243f4a2713aSLionel Sambuc   if (Invocation->getHeaderSearchOpts().Verbose) {
244f4a2713aSLionel Sambuc     llvm::errs() << "clang Invocation:\n";
245f4a2713aSLionel Sambuc     Compilation->getJobs().Print(llvm::errs(), "\n", true);
246f4a2713aSLionel Sambuc     llvm::errs() << "\n";
247f4a2713aSLionel Sambuc   }
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc   return Action->runInvocation(Invocation, Files, DiagConsumer);
250f4a2713aSLionel Sambuc }
251f4a2713aSLionel Sambuc 
runInvocation(CompilerInvocation * Invocation,FileManager * Files,DiagnosticConsumer * DiagConsumer)252f4a2713aSLionel Sambuc bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
253f4a2713aSLionel Sambuc                                           FileManager *Files,
254f4a2713aSLionel Sambuc                                           DiagnosticConsumer *DiagConsumer) {
255f4a2713aSLionel Sambuc   // Create a compiler instance to handle the actual work.
256f4a2713aSLionel Sambuc   clang::CompilerInstance Compiler;
257f4a2713aSLionel Sambuc   Compiler.setInvocation(Invocation);
258f4a2713aSLionel Sambuc   Compiler.setFileManager(Files);
259f4a2713aSLionel Sambuc 
260f4a2713aSLionel Sambuc   // The FrontendAction can have lifetime requirements for Compiler or its
261f4a2713aSLionel Sambuc   // members, and we need to ensure it's deleted earlier than Compiler. So we
262*0a6a1f1dSLionel Sambuc   // pass it to an std::unique_ptr declared after the Compiler variable.
263*0a6a1f1dSLionel Sambuc   std::unique_ptr<FrontendAction> ScopedToolAction(create());
264f4a2713aSLionel Sambuc 
265*0a6a1f1dSLionel Sambuc   // Create the compiler's actual diagnostics engine.
266f4a2713aSLionel Sambuc   Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
267f4a2713aSLionel Sambuc   if (!Compiler.hasDiagnostics())
268f4a2713aSLionel Sambuc     return false;
269f4a2713aSLionel Sambuc 
270f4a2713aSLionel Sambuc   Compiler.createSourceManager(*Files);
271f4a2713aSLionel Sambuc 
272f4a2713aSLionel Sambuc   const bool Success = Compiler.ExecuteAction(*ScopedToolAction);
273f4a2713aSLionel Sambuc 
274f4a2713aSLionel Sambuc   Files->clearStatCaches();
275f4a2713aSLionel Sambuc   return Success;
276f4a2713aSLionel Sambuc }
277f4a2713aSLionel Sambuc 
ClangTool(const CompilationDatabase & Compilations,ArrayRef<std::string> SourcePaths)278f4a2713aSLionel Sambuc ClangTool::ClangTool(const CompilationDatabase &Compilations,
279f4a2713aSLionel Sambuc                      ArrayRef<std::string> SourcePaths)
280*0a6a1f1dSLionel Sambuc     : Compilations(Compilations), SourcePaths(SourcePaths),
281*0a6a1f1dSLionel Sambuc       Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
282*0a6a1f1dSLionel Sambuc   appendArgumentsAdjuster(getClangStripOutputAdjuster());
283*0a6a1f1dSLionel Sambuc   appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
284f4a2713aSLionel Sambuc }
285f4a2713aSLionel Sambuc 
~ClangTool()286*0a6a1f1dSLionel Sambuc ClangTool::~ClangTool() {}
287f4a2713aSLionel Sambuc 
mapVirtualFile(StringRef FilePath,StringRef Content)288f4a2713aSLionel Sambuc void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
289f4a2713aSLionel Sambuc   MappedFileContents.push_back(std::make_pair(FilePath, Content));
290f4a2713aSLionel Sambuc }
291f4a2713aSLionel Sambuc 
appendArgumentsAdjuster(ArgumentsAdjuster Adjuster)292*0a6a1f1dSLionel Sambuc void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
293*0a6a1f1dSLionel Sambuc   if (ArgsAdjuster)
294*0a6a1f1dSLionel Sambuc     ArgsAdjuster = combineAdjusters(ArgsAdjuster, Adjuster);
295*0a6a1f1dSLionel Sambuc   else
296*0a6a1f1dSLionel Sambuc     ArgsAdjuster = Adjuster;
297f4a2713aSLionel Sambuc }
298f4a2713aSLionel Sambuc 
clearArgumentsAdjusters()299f4a2713aSLionel Sambuc void ClangTool::clearArgumentsAdjusters() {
300*0a6a1f1dSLionel Sambuc   ArgsAdjuster = nullptr;
301f4a2713aSLionel Sambuc }
302f4a2713aSLionel Sambuc 
run(ToolAction * Action)303f4a2713aSLionel Sambuc int ClangTool::run(ToolAction *Action) {
304f4a2713aSLionel Sambuc   // Exists solely for the purpose of lookup of the resource path.
305f4a2713aSLionel Sambuc   // This just needs to be some symbol in the binary.
306f4a2713aSLionel Sambuc   static int StaticSymbol;
307f4a2713aSLionel Sambuc   // The driver detects the builtin header path based on the path of the
308f4a2713aSLionel Sambuc   // executable.
309f4a2713aSLionel Sambuc   // FIXME: On linux, GetMainExecutable is independent of the value of the
310f4a2713aSLionel Sambuc   // first argument, thus allowing ClangTool and runToolOnCode to just
311f4a2713aSLionel Sambuc   // pass in made-up names here. Make sure this works on other platforms.
312f4a2713aSLionel Sambuc   std::string MainExecutable =
313f4a2713aSLionel Sambuc       llvm::sys::fs::getMainExecutable("clang_tool", &StaticSymbol);
314f4a2713aSLionel Sambuc 
315*0a6a1f1dSLionel Sambuc   llvm::SmallString<128> InitialDirectory;
316*0a6a1f1dSLionel Sambuc   if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
317*0a6a1f1dSLionel Sambuc     llvm::report_fatal_error("Cannot detect current path: " +
318*0a6a1f1dSLionel Sambuc                              Twine(EC.message()));
319f4a2713aSLionel Sambuc   bool ProcessingFailed = false;
320*0a6a1f1dSLionel Sambuc   for (const auto &SourcePath : SourcePaths) {
321*0a6a1f1dSLionel Sambuc     std::string File(getAbsolutePath(SourcePath));
322*0a6a1f1dSLionel Sambuc 
323*0a6a1f1dSLionel Sambuc     // Currently implementations of CompilationDatabase::getCompileCommands can
324*0a6a1f1dSLionel Sambuc     // change the state of the file system (e.g.  prepare generated headers), so
325*0a6a1f1dSLionel Sambuc     // this method needs to run right before we invoke the tool, as the next
326*0a6a1f1dSLionel Sambuc     // file may require a different (incompatible) state of the file system.
327*0a6a1f1dSLionel Sambuc     //
328*0a6a1f1dSLionel Sambuc     // FIXME: Make the compilation database interface more explicit about the
329*0a6a1f1dSLionel Sambuc     // requirements to the order of invocation of its members.
330*0a6a1f1dSLionel Sambuc     std::vector<CompileCommand> CompileCommandsForFile =
331*0a6a1f1dSLionel Sambuc         Compilations.getCompileCommands(File);
332*0a6a1f1dSLionel Sambuc     if (CompileCommandsForFile.empty()) {
333*0a6a1f1dSLionel Sambuc       // FIXME: There are two use cases here: doing a fuzzy
334*0a6a1f1dSLionel Sambuc       // "find . -name '*.cc' |xargs tool" match, where as a user I don't care
335*0a6a1f1dSLionel Sambuc       // about the .cc files that were not found, and the use case where I
336*0a6a1f1dSLionel Sambuc       // specify all files I want to run over explicitly, where this should
337*0a6a1f1dSLionel Sambuc       // be an error. We'll want to add an option for this.
338*0a6a1f1dSLionel Sambuc       llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
339*0a6a1f1dSLionel Sambuc       continue;
340*0a6a1f1dSLionel Sambuc     }
341*0a6a1f1dSLionel Sambuc     for (CompileCommand &CompileCommand : CompileCommandsForFile) {
342f4a2713aSLionel Sambuc       // FIXME: chdir is thread hostile; on the other hand, creating the same
343f4a2713aSLionel Sambuc       // behavior as chdir is complex: chdir resolves the path once, thus
344f4a2713aSLionel Sambuc       // guaranteeing that all subsequent relative path operations work
345*0a6a1f1dSLionel Sambuc       // on the same path the original chdir resulted in. This makes a
346*0a6a1f1dSLionel Sambuc       // difference for example on network filesystems, where symlinks might be
347*0a6a1f1dSLionel Sambuc       // switched during runtime of the tool. Fixing this depends on having a
348*0a6a1f1dSLionel Sambuc       // file system abstraction that allows openat() style interactions.
349*0a6a1f1dSLionel Sambuc       if (chdir(CompileCommand.Directory.c_str()))
350f4a2713aSLionel Sambuc         llvm::report_fatal_error("Cannot chdir into \"" +
351*0a6a1f1dSLionel Sambuc                                  Twine(CompileCommand.Directory) + "\n!");
352*0a6a1f1dSLionel Sambuc       std::vector<std::string> CommandLine = CompileCommand.CommandLine;
353*0a6a1f1dSLionel Sambuc       if (ArgsAdjuster)
354*0a6a1f1dSLionel Sambuc         CommandLine = ArgsAdjuster(CommandLine);
355f4a2713aSLionel Sambuc       assert(!CommandLine.empty());
356f4a2713aSLionel Sambuc       CommandLine[0] = MainExecutable;
357f4a2713aSLionel Sambuc       // FIXME: We need a callback mechanism for the tool writer to output a
358f4a2713aSLionel Sambuc       // customized message for each file.
359*0a6a1f1dSLionel Sambuc       DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
360*0a6a1f1dSLionel Sambuc       ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
361f4a2713aSLionel Sambuc       Invocation.setDiagnosticConsumer(DiagConsumer);
362*0a6a1f1dSLionel Sambuc       for (const auto &MappedFile : MappedFileContents)
363*0a6a1f1dSLionel Sambuc         Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
364f4a2713aSLionel Sambuc       if (!Invocation.run()) {
365f4a2713aSLionel Sambuc         // FIXME: Diagnostics should be used instead.
366f4a2713aSLionel Sambuc         llvm::errs() << "Error while processing " << File << ".\n";
367f4a2713aSLionel Sambuc         ProcessingFailed = true;
368f4a2713aSLionel Sambuc       }
369*0a6a1f1dSLionel Sambuc       // Return to the initial directory to correctly resolve next file by
370*0a6a1f1dSLionel Sambuc       // relative path.
371*0a6a1f1dSLionel Sambuc       if (chdir(InitialDirectory.c_str()))
372*0a6a1f1dSLionel Sambuc         llvm::report_fatal_error("Cannot chdir into \"" +
373*0a6a1f1dSLionel Sambuc                                  Twine(InitialDirectory) + "\n!");
374*0a6a1f1dSLionel Sambuc     }
375f4a2713aSLionel Sambuc   }
376f4a2713aSLionel Sambuc   return ProcessingFailed ? 1 : 0;
377f4a2713aSLionel Sambuc }
378f4a2713aSLionel Sambuc 
379f4a2713aSLionel Sambuc namespace {
380f4a2713aSLionel Sambuc 
381f4a2713aSLionel Sambuc class ASTBuilderAction : public ToolAction {
382*0a6a1f1dSLionel Sambuc   std::vector<std::unique_ptr<ASTUnit>> &ASTs;
383f4a2713aSLionel Sambuc 
384f4a2713aSLionel Sambuc public:
ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> & ASTs)385*0a6a1f1dSLionel Sambuc   ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
386f4a2713aSLionel Sambuc 
runInvocation(CompilerInvocation * Invocation,FileManager * Files,DiagnosticConsumer * DiagConsumer)387f4a2713aSLionel Sambuc   bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
388*0a6a1f1dSLionel Sambuc                      DiagnosticConsumer *DiagConsumer) override {
389f4a2713aSLionel Sambuc     // FIXME: This should use the provided FileManager.
390*0a6a1f1dSLionel Sambuc     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
391f4a2713aSLionel Sambuc         Invocation, CompilerInstance::createDiagnostics(
392f4a2713aSLionel Sambuc                         &Invocation->getDiagnosticOpts(), DiagConsumer,
393f4a2713aSLionel Sambuc                         /*ShouldOwnClient=*/false));
394f4a2713aSLionel Sambuc     if (!AST)
395f4a2713aSLionel Sambuc       return false;
396f4a2713aSLionel Sambuc 
397*0a6a1f1dSLionel Sambuc     ASTs.push_back(std::move(AST));
398f4a2713aSLionel Sambuc     return true;
399f4a2713aSLionel Sambuc   }
400f4a2713aSLionel Sambuc };
401f4a2713aSLionel Sambuc 
402f4a2713aSLionel Sambuc }
403f4a2713aSLionel Sambuc 
buildASTs(std::vector<std::unique_ptr<ASTUnit>> & ASTs)404*0a6a1f1dSLionel Sambuc int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
405f4a2713aSLionel Sambuc   ASTBuilderAction Action(ASTs);
406f4a2713aSLionel Sambuc   return run(&Action);
407f4a2713aSLionel Sambuc }
408f4a2713aSLionel Sambuc 
buildASTFromCode(const Twine & Code,const Twine & FileName)409*0a6a1f1dSLionel Sambuc std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code,
410*0a6a1f1dSLionel Sambuc                                           const Twine &FileName) {
411f4a2713aSLionel Sambuc   return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName);
412f4a2713aSLionel Sambuc }
413f4a2713aSLionel Sambuc 
414*0a6a1f1dSLionel Sambuc std::unique_ptr<ASTUnit>
buildASTFromCodeWithArgs(const Twine & Code,const std::vector<std::string> & Args,const Twine & FileName)415*0a6a1f1dSLionel Sambuc buildASTFromCodeWithArgs(const Twine &Code,
416f4a2713aSLionel Sambuc                          const std::vector<std::string> &Args,
417f4a2713aSLionel Sambuc                          const Twine &FileName) {
418f4a2713aSLionel Sambuc   SmallString<16> FileNameStorage;
419f4a2713aSLionel Sambuc   StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
420f4a2713aSLionel Sambuc 
421*0a6a1f1dSLionel Sambuc   std::vector<std::unique_ptr<ASTUnit>> ASTs;
422f4a2713aSLionel Sambuc   ASTBuilderAction Action(ASTs);
423*0a6a1f1dSLionel Sambuc   ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action,
424*0a6a1f1dSLionel Sambuc                             nullptr);
425f4a2713aSLionel Sambuc 
426f4a2713aSLionel Sambuc   SmallString<1024> CodeStorage;
427f4a2713aSLionel Sambuc   Invocation.mapVirtualFile(FileNameRef,
428f4a2713aSLionel Sambuc                             Code.toNullTerminatedStringRef(CodeStorage));
429f4a2713aSLionel Sambuc   if (!Invocation.run())
430*0a6a1f1dSLionel Sambuc     return nullptr;
431f4a2713aSLionel Sambuc 
432f4a2713aSLionel Sambuc   assert(ASTs.size() == 1);
433*0a6a1f1dSLionel Sambuc   return std::move(ASTs[0]);
434f4a2713aSLionel Sambuc }
435f4a2713aSLionel Sambuc 
436f4a2713aSLionel Sambuc } // end namespace tooling
437f4a2713aSLionel Sambuc } // end namespace clang
438