clang  10.0.0svn
Tooling.cpp
Go to the documentation of this file.
1 //===- Tooling.cpp - Running clang standalone tools -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements functions to run clang tools standalone instead
10 // of running them as a plugin.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Tooling/Tooling.h"
15 #include "clang/Basic/Diagnostic.h"
20 #include "clang/Basic/LLVM.h"
22 #include "clang/Driver/Driver.h"
23 #include "clang/Driver/Job.h"
24 #include "clang/Driver/Options.h"
25 #include "clang/Driver/Tool.h"
26 #include "clang/Driver/ToolChain.h"
27 #include "clang/Frontend/ASTUnit.h"
37 #include "llvm/ADT/ArrayRef.h"
38 #include "llvm/ADT/IntrusiveRefCntPtr.h"
39 #include "llvm/ADT/SmallString.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/Casting.h"
46 #include "llvm/Support/Debug.h"
47 #include "llvm/Support/ErrorHandling.h"
48 #include "llvm/Support/FileSystem.h"
49 #include "llvm/Support/Host.h"
50 #include "llvm/Support/MemoryBuffer.h"
51 #include "llvm/Support/Path.h"
52 #include "llvm/Support/VirtualFileSystem.h"
53 #include "llvm/Support/raw_ostream.h"
54 #include <cassert>
55 #include <cstring>
56 #include <memory>
57 #include <string>
58 #include <system_error>
59 #include <utility>
60 #include <vector>
61 
62 #define DEBUG_TYPE "clang-tooling"
63 
64 using namespace clang;
65 using namespace tooling;
66 
67 ToolAction::~ToolAction() = default;
68 
70 
71 // FIXME: This file contains structural duplication with other parts of the
72 // code that sets up a compiler to run tools on it, and we should refactor
73 // it to be based on the same framework.
74 
75 /// Builds a clang driver initialized for running clang tools.
76 static driver::Driver *
77 newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName,
79  driver::Driver *CompilerDriver =
80  new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(),
81  *Diagnostics, std::move(VFS));
82  CompilerDriver->setTitle("clang_based_tool");
83  return CompilerDriver;
84 }
85 
86 /// Retrieves the clang CC1 specific flags out of the compilation's jobs.
87 ///
88 /// Returns nullptr on error.
89 static const llvm::opt::ArgStringList *getCC1Arguments(
90  DiagnosticsEngine *Diagnostics, driver::Compilation *Compilation) {
91  // We expect to get back exactly one Command job, if we didn't something
92  // failed. Extract that job from the Compilation.
93  const driver::JobList &Jobs = Compilation->getJobs();
94  const driver::ActionList &Actions = Compilation->getActions();
95  bool OffloadCompilation = false;
96  if (Jobs.size() > 1) {
97  for (auto A : Actions){
98  // On MacOSX real actions may end up being wrapped in BindArchAction
99  if (isa<driver::BindArchAction>(A))
100  A = *A->input_begin();
101  if (isa<driver::OffloadAction>(A)) {
102  // Offload compilation has 2 top-level actions, one (at the front) is
103  // the original host compilation and the other is offload action
104  // composed of at least one device compilation. For such case, general
105  // tooling will consider host-compilation only. For tooling on device
106  // compilation, device compilation only option, such as
107  // `--cuda-device-only`, needs specifying.
108  assert(Actions.size() > 1);
109  assert(
110  isa<driver::CompileJobAction>(Actions.front()) ||
111  // On MacOSX real actions may end up being wrapped in
112  // BindArchAction.
113  (isa<driver::BindArchAction>(Actions.front()) &&
114  isa<driver::CompileJobAction>(*Actions.front()->input_begin())));
115  OffloadCompilation = true;
116  break;
117  }
118  }
119  }
120  if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
121  (Jobs.size() > 1 && !OffloadCompilation)) {
122  SmallString<256> error_msg;
123  llvm::raw_svector_ostream error_stream(error_msg);
124  Jobs.Print(error_stream, "; ", true);
125  Diagnostics->Report(diag::err_fe_expected_compiler_job)
126  << error_stream.str();
127  return nullptr;
128  }
129 
130  // The one job we find should be to invoke clang again.
131  const auto &Cmd = cast<driver::Command>(*Jobs.begin());
132  if (StringRef(Cmd.getCreator().getName()) != "clang") {
133  Diagnostics->Report(diag::err_fe_expected_clang_command);
134  return nullptr;
135  }
136 
137  return &Cmd.getArguments();
138 }
139 
140 namespace clang {
141 namespace tooling {
142 
143 /// Returns a clang build invocation initialized from the CC1 flags.
145  DiagnosticsEngine *Diagnostics, const llvm::opt::ArgStringList &CC1Args) {
146  assert(!CC1Args.empty() && "Must at least contain the program name!");
147  CompilerInvocation *Invocation = new CompilerInvocation;
148  CompilerInvocation::CreateFromArgs(*Invocation, CC1Args, *Diagnostics);
149  Invocation->getFrontendOpts().DisableFree = false;
150  Invocation->getCodeGenOpts().DisableFree = false;
151  return Invocation;
152 }
153 
154 bool runToolOnCode(std::unique_ptr<FrontendAction> ToolAction,
155  const Twine &Code, const Twine &FileName,
156  std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
157  return runToolOnCodeWithArgs(std::move(ToolAction), Code,
158  std::vector<std::string>(), FileName,
159  "clang-tool", std::move(PCHContainerOps));
160 }
161 
162 } // namespace tooling
163 } // namespace clang
164 
165 static std::vector<std::string>
166 getSyntaxOnlyToolArgs(const Twine &ToolName,
167  const std::vector<std::string> &ExtraArgs,
168  StringRef FileName) {
169  std::vector<std::string> Args;
170  Args.push_back(ToolName.str());
171  Args.push_back("-fsyntax-only");
172  Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
173  Args.push_back(FileName.str());
174  return Args;
175 }
176 
177 namespace clang {
178 namespace tooling {
179 
181  std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
183  const std::vector<std::string> &Args, const Twine &FileName,
184  const Twine &ToolName,
185  std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
186  SmallString<16> FileNameStorage;
187  StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
188 
190  new FileManager(FileSystemOptions(), VFS));
192  ToolInvocation Invocation(
193  getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
194  std::move(ToolAction), Files.get(), std::move(PCHContainerOps));
195  return Invocation.run();
196 }
197 
199  std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
200  const std::vector<std::string> &Args, const Twine &FileName,
201  const Twine &ToolName,
202  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
203  const FileContentMappings &VirtualMappedFiles) {
205  new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
207  new llvm::vfs::InMemoryFileSystem);
208  OverlayFileSystem->pushOverlay(InMemoryFileSystem);
209 
210  SmallString<1024> CodeStorage;
211  InMemoryFileSystem->addFile(FileName, 0,
212  llvm::MemoryBuffer::getMemBuffer(
213  Code.toNullTerminatedStringRef(CodeStorage)));
214 
215  for (auto &FilenameWithContent : VirtualMappedFiles) {
216  InMemoryFileSystem->addFile(
217  FilenameWithContent.first, 0,
218  llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
219  }
220 
221  return runToolOnCodeWithArgs(std::move(ToolAction), Code, OverlayFileSystem,
222  Args, FileName, ToolName);
223 }
224 
226  StringRef File) {
227  StringRef RelativePath(File);
228  // FIXME: Should '.\\' be accepted on Win32?
229  if (RelativePath.startswith("./")) {
230  RelativePath = RelativePath.substr(strlen("./"));
231  }
232 
233  SmallString<1024> AbsolutePath = RelativePath;
234  if (auto EC = FS.makeAbsolute(AbsolutePath))
235  return llvm::errorCodeToError(EC);
236  llvm::sys::path::native(AbsolutePath);
237  return AbsolutePath.str();
238 }
239 
240 std::string getAbsolutePath(StringRef File) {
241  return llvm::cantFail(getAbsolutePath(*llvm::vfs::getRealFileSystem(), File));
242 }
243 
244 void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
245  StringRef InvokedAs) {
246  if (!CommandLine.empty() && !InvokedAs.empty()) {
247  bool AlreadyHasTarget = false;
248  bool AlreadyHasMode = false;
249  // Skip CommandLine[0].
250  for (auto Token = ++CommandLine.begin(); Token != CommandLine.end();
251  ++Token) {
252  StringRef TokenRef(*Token);
253  AlreadyHasTarget |=
254  (TokenRef == "-target" || TokenRef.startswith("-target="));
255  AlreadyHasMode |= (TokenRef == "--driver-mode" ||
256  TokenRef.startswith("--driver-mode="));
257  }
258  auto TargetMode =
260  if (!AlreadyHasMode && TargetMode.DriverMode) {
261  CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
262  }
263  if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
264  CommandLine.insert(++CommandLine.begin(), {"-target",
265  TargetMode.TargetPrefix});
266  }
267  }
268 }
269 
270 } // namespace tooling
271 } // namespace clang
272 
273 namespace {
274 
275 class SingleFrontendActionFactory : public FrontendActionFactory {
276  std::unique_ptr<FrontendAction> Action;
277 
278 public:
279  SingleFrontendActionFactory(std::unique_ptr<FrontendAction> Action)
280  : Action(std::move(Action)) {}
281 
282  std::unique_ptr<FrontendAction> create() override {
283  return std::move(Action);
284  }
285 };
286 
287 } // namespace
288 
290  std::vector<std::string> CommandLine, ToolAction *Action,
291  FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
292  : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(false),
293  Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
294 
296  std::vector<std::string> CommandLine,
297  std::unique_ptr<FrontendAction> FAction, FileManager *Files,
298  std::shared_ptr<PCHContainerOperations> PCHContainerOps)
299  : CommandLine(std::move(CommandLine)),
300  Action(new SingleFrontendActionFactory(std::move(FAction))),
301  OwnsAction(true), Files(Files),
302  PCHContainerOps(std::move(PCHContainerOps)) {}
303 
305  if (OwnsAction)
306  delete Action;
307 }
308 
309 void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
310  SmallString<1024> PathStorage;
311  llvm::sys::path::native(FilePath, PathStorage);
312  MappedFileContents[PathStorage] = Content;
313 }
314 
316  std::vector<const char*> Argv;
317  for (const std::string &Str : CommandLine)
318  Argv.push_back(Str.c_str());
319  const char *const BinaryName = Argv[0];
321  unsigned MissingArgIndex, MissingArgCount;
322  llvm::opt::InputArgList ParsedArgs = driver::getDriverOptTable().ParseArgs(
323  ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount);
324  ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
325  TextDiagnosticPrinter DiagnosticPrinter(
326  llvm::errs(), &*DiagOpts);
327  DiagnosticsEngine Diagnostics(
329  DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
330 
331  const std::unique_ptr<driver::Driver> Driver(
332  newDriver(&Diagnostics, BinaryName, &Files->getVirtualFileSystem()));
333  // The "input file not found" diagnostics from the driver are useful.
334  // The driver is only aware of the VFS working directory, but some clients
335  // change this at the FileManager level instead.
336  // In this case the checks have false positives, so skip them.
337  if (!Files->getFileSystemOpts().WorkingDir.empty())
338  Driver->setCheckInputsExist(false);
339  const std::unique_ptr<driver::Compilation> Compilation(
340  Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
341  if (!Compilation)
342  return false;
343  const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
344  &Diagnostics, Compilation.get());
345  if (!CC1Args)
346  return false;
347  std::unique_ptr<CompilerInvocation> Invocation(
348  newInvocation(&Diagnostics, *CC1Args));
349  // FIXME: remove this when all users have migrated!
350  for (const auto &It : MappedFileContents) {
351  // Inject the code as the given file name into the preprocessor options.
352  std::unique_ptr<llvm::MemoryBuffer> Input =
353  llvm::MemoryBuffer::getMemBuffer(It.getValue());
354  Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
355  Input.release());
356  }
357  return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
358  std::move(PCHContainerOps));
359 }
360 
361 bool ToolInvocation::runInvocation(
362  const char *BinaryName, driver::Compilation *Compilation,
363  std::shared_ptr<CompilerInvocation> Invocation,
364  std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
365  // Show the invocation, with -v.
366  if (Invocation->getHeaderSearchOpts().Verbose) {
367  llvm::errs() << "clang Invocation:\n";
368  Compilation->getJobs().Print(llvm::errs(), "\n", true);
369  llvm::errs() << "\n";
370  }
371 
372  return Action->runInvocation(std::move(Invocation), Files,
373  std::move(PCHContainerOps), DiagConsumer);
374 }
375 
377  std::shared_ptr<CompilerInvocation> Invocation, FileManager *Files,
378  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
379  DiagnosticConsumer *DiagConsumer) {
380  // Create a compiler instance to handle the actual work.
381  CompilerInstance Compiler(std::move(PCHContainerOps));
382  Compiler.setInvocation(std::move(Invocation));
383  Compiler.setFileManager(Files);
384 
385  // The FrontendAction can have lifetime requirements for Compiler or its
386  // members, and we need to ensure it's deleted earlier than Compiler. So we
387  // pass it to an std::unique_ptr declared after the Compiler variable.
388  std::unique_ptr<FrontendAction> ScopedToolAction(create());
389 
390  // Create the compiler's actual diagnostics engine.
391  Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
392  if (!Compiler.hasDiagnostics())
393  return false;
394 
395  Compiler.createSourceManager(*Files);
396 
397  const bool Success = Compiler.ExecuteAction(*ScopedToolAction);
398 
399  Files->clearStatCache();
400  return Success;
401 }
402 
404  ArrayRef<std::string> SourcePaths,
405  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
408  : Compilations(Compilations), SourcePaths(SourcePaths),
409  PCHContainerOps(std::move(PCHContainerOps)),
410  OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
411  InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
412  Files(Files ? Files
413  : new FileManager(FileSystemOptions(), OverlayFileSystem)) {
414  OverlayFileSystem->pushOverlay(InMemoryFileSystem);
418  if (Files)
419  Files->setVirtualFileSystem(OverlayFileSystem);
420 }
421 
422 ClangTool::~ClangTool() = default;
423 
424 void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
425  MappedFileContents.push_back(std::make_pair(FilePath, Content));
426 }
427 
429  ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
430 }
431 
433  ArgsAdjuster = nullptr;
434 }
435 
436 static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
437  void *MainAddr) {
438  // Allow users to override the resource dir.
439  for (StringRef Arg : Args)
440  if (Arg.startswith("-resource-dir"))
441  return;
442 
443  // If there's no override in place add our resource dir.
444  Args.push_back("-resource-dir=" +
445  CompilerInvocation::GetResourcesPath(Argv0, MainAddr));
446 }
447 
449  // Exists solely for the purpose of lookup of the resource path.
450  // This just needs to be some symbol in the binary.
451  static int StaticSymbol;
452 
453  // First insert all absolute paths into the in-memory VFS. These are global
454  // for all compile commands.
455  if (SeenWorkingDirectories.insert("/").second)
456  for (const auto &MappedFile : MappedFileContents)
457  if (llvm::sys::path::is_absolute(MappedFile.first))
458  InMemoryFileSystem->addFile(
459  MappedFile.first, 0,
460  llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
461 
462  bool ProcessingFailed = false;
463  bool FileSkipped = false;
464  // Compute all absolute paths before we run any actions, as those will change
465  // the working directory.
466  std::vector<std::string> AbsolutePaths;
467  AbsolutePaths.reserve(SourcePaths.size());
468  for (const auto &SourcePath : SourcePaths) {
469  auto AbsPath = getAbsolutePath(*OverlayFileSystem, SourcePath);
470  if (!AbsPath) {
471  llvm::errs() << "Skipping " << SourcePath
472  << ". Error while getting an absolute path: "
473  << llvm::toString(AbsPath.takeError()) << "\n";
474  continue;
475  }
476  AbsolutePaths.push_back(std::move(*AbsPath));
477  }
478 
479  // Remember the working directory in case we need to restore it.
480  std::string InitialWorkingDir;
481  if (RestoreCWD) {
482  if (auto CWD = OverlayFileSystem->getCurrentWorkingDirectory()) {
483  InitialWorkingDir = std::move(*CWD);
484  } else {
485  llvm::errs() << "Could not get working directory: "
486  << CWD.getError().message() << "\n";
487  }
488  }
489 
490  for (llvm::StringRef File : AbsolutePaths) {
491  // Currently implementations of CompilationDatabase::getCompileCommands can
492  // change the state of the file system (e.g. prepare generated headers), so
493  // this method needs to run right before we invoke the tool, as the next
494  // file may require a different (incompatible) state of the file system.
495  //
496  // FIXME: Make the compilation database interface more explicit about the
497  // requirements to the order of invocation of its members.
498  std::vector<CompileCommand> CompileCommandsForFile =
499  Compilations.getCompileCommands(File);
500  if (CompileCommandsForFile.empty()) {
501  llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
502  FileSkipped = true;
503  continue;
504  }
505  for (CompileCommand &CompileCommand : CompileCommandsForFile) {
506  // FIXME: chdir is thread hostile; on the other hand, creating the same
507  // behavior as chdir is complex: chdir resolves the path once, thus
508  // guaranteeing that all subsequent relative path operations work
509  // on the same path the original chdir resulted in. This makes a
510  // difference for example on network filesystems, where symlinks might be
511  // switched during runtime of the tool. Fixing this depends on having a
512  // file system abstraction that allows openat() style interactions.
513  if (OverlayFileSystem->setCurrentWorkingDirectory(
515  llvm::report_fatal_error("Cannot chdir into \"" +
516  Twine(CompileCommand.Directory) + "\"!");
517 
518  // Now fill the in-memory VFS with the relative file mappings so it will
519  // have the correct relative paths. We never remove mappings but that
520  // should be fine.
521  if (SeenWorkingDirectories.insert(CompileCommand.Directory).second)
522  for (const auto &MappedFile : MappedFileContents)
523  if (!llvm::sys::path::is_absolute(MappedFile.first))
524  InMemoryFileSystem->addFile(
525  MappedFile.first, 0,
526  llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
527 
528  std::vector<std::string> CommandLine = CompileCommand.CommandLine;
529  if (ArgsAdjuster)
530  CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename);
531  assert(!CommandLine.empty());
532 
533  // Add the resource dir based on the binary of this tool. argv[0] in the
534  // compilation database may refer to a different compiler and we want to
535  // pick up the very same standard library that compiler is using. The
536  // builtin headers in the resource dir need to match the exact clang
537  // version the tool is using.
538  // FIXME: On linux, GetMainExecutable is independent of the value of the
539  // first argument, thus allowing ClangTool and runToolOnCode to just
540  // pass in made-up names here. Make sure this works on other platforms.
541  injectResourceDir(CommandLine, "clang_tool", &StaticSymbol);
542 
543  // FIXME: We need a callback mechanism for the tool writer to output a
544  // customized message for each file.
545  LLVM_DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
546  ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
547  PCHContainerOps);
548  Invocation.setDiagnosticConsumer(DiagConsumer);
549 
550  if (!Invocation.run()) {
551  // FIXME: Diagnostics should be used instead.
552  if (PrintErrorMessage)
553  llvm::errs() << "Error while processing " << File << ".\n";
554  ProcessingFailed = true;
555  }
556  }
557  }
558 
559  if (!InitialWorkingDir.empty()) {
560  if (auto EC =
561  OverlayFileSystem->setCurrentWorkingDirectory(InitialWorkingDir))
562  llvm::errs() << "Error when trying to restore working dir: "
563  << EC.message() << "\n";
564  }
565  return ProcessingFailed ? 1 : (FileSkipped ? 2 : 0);
566 }
567 
568 namespace {
569 
570 class ASTBuilderAction : public ToolAction {
571  std::vector<std::unique_ptr<ASTUnit>> &ASTs;
572 
573 public:
574  ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
575 
576  bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
577  FileManager *Files,
578  std::shared_ptr<PCHContainerOperations> PCHContainerOps,
579  DiagnosticConsumer *DiagConsumer) override {
580  std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
581  Invocation, std::move(PCHContainerOps),
582  CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
583  DiagConsumer,
584  /*ShouldOwnClient=*/false),
585  Files);
586  if (!AST)
587  return false;
588 
589  ASTs.push_back(std::move(AST));
590  return true;
591  }
592 };
593 
594 } // namespace
595 
596 int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
597  ASTBuilderAction Action(ASTs);
598  return run(&Action);
599 }
600 
601 void ClangTool::setRestoreWorkingDir(bool RestoreCWD) {
602  this->RestoreCWD = RestoreCWD;
603 }
604 
605 void ClangTool::setPrintErrorMessage(bool PrintErrorMessage) {
606  this->PrintErrorMessage = PrintErrorMessage;
607 }
608 
609 namespace clang {
610 namespace tooling {
611 
612 std::unique_ptr<ASTUnit>
613 buildASTFromCode(StringRef Code, StringRef FileName,
614  std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
615  return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName,
616  "clang-tool", std::move(PCHContainerOps));
617 }
618 
619 std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
620  StringRef Code, const std::vector<std::string> &Args, StringRef FileName,
621  StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps,
622  ArgumentsAdjuster Adjuster) {
623  std::vector<std::unique_ptr<ASTUnit>> ASTs;
624  ASTBuilderAction Action(ASTs);
626  new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
628  new llvm::vfs::InMemoryFileSystem);
629  OverlayFileSystem->pushOverlay(InMemoryFileSystem);
631  new FileManager(FileSystemOptions(), OverlayFileSystem));
632 
633  ToolInvocation Invocation(
634  getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName),
635  &Action, Files.get(), std::move(PCHContainerOps));
636 
637  InMemoryFileSystem->addFile(FileName, 0,
638  llvm::MemoryBuffer::getMemBufferCopy(Code));
639  if (!Invocation.run())
640  return nullptr;
641 
642  assert(ASTs.size() == 1);
643  return std::move(ASTs[0]);
644 }
645 
646 } // namespace tooling
647 } // namespace clang
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.
std::vector< std::string > CommandLineArguments
A sequence of command line arguments.
Interface to process a clang::CompilerInvocation.
Definition: Tooling.h:73
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:171
Defines the clang::FileManager interface and associated types.
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
Definition: Dominators.h:30
void createDiagnostics(DiagnosticConsumer *Client=nullptr, bool ShouldOwnClient=true)
Create the diagnostics engine using the invocation&#39;s diagnostic options and replace any existing one ...
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1290
static std::vector< std::string > getSyntaxOnlyToolArgs(const Twine &ToolName, const std::vector< std::string > &ExtraArgs, StringRef FileName)
Definition: Tooling.cpp:166
static ParsedClangName getTargetAndModeFromProgramName(StringRef ProgName)
Return any implicit target and/or mode flag for an invocation of the compiler driver as ProgName...
Definition: ToolChain.cpp:204
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1489
ArgumentsAdjuster getClangStripDependencyFileAdjuster()
Gets an argument adjuster which removes dependency-file related command line arguments.
static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, void *MainAddr)
Definition: Tooling.cpp:436
ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, ArgumentsAdjuster Second)
Gets an argument adjuster which adjusts the arguments in sequence with the First adjuster and then wi...
Interface to generate clang::FrontendActions.
Definition: Tooling.h:91
void createSourceManager(FileManager &FileMgr)
Create the source manager and replace any existing one with it.
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Definition: Format.h:2392
void clearArgumentsAdjusters()
Clear the command line arguments adjuster chain.
Definition: Tooling.cpp:432
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
ClangTool(const CompilationDatabase &Compilations, ArrayRef< std::string > SourcePaths, std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >(), IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS=llvm::vfs::getRealFileSystem(), IntrusiveRefCntPtr< FileManager > Files=nullptr)
Constructs a clang tool to run over a list of files.
Definition: Tooling.cpp:403
std::string Directory
The working directory the command was executed from.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
CompileCommand Cmd
Defines the Diagnostic-related interfaces.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:59
void setFileManager(FileManager *Value)
Replace the current file manager and virtual file system.
static driver::Driver * newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS)
Builds a clang driver initialized for running clang tools.
Definition: Tooling.cpp:77
void setPrintErrorMessage(bool PrintErrorMessage)
Sets whether an error message should be printed out if an action fails.
Definition: Tooling.cpp:605
bool run()
Run the clang invocation.
Definition: Tooling.cpp:315
const llvm::opt::OptTable & getDriverOptTable()
ArgumentsAdjuster getClangStripOutputAdjuster()
Gets an argument adjuster which removes output-related command line arguments.
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...
std::string Filename
The source file associated with the command.
int buildASTs(std::vector< std::unique_ptr< ASTUnit >> &ASTs)
Create an AST for each file specified in the command line and append them to ASTs.
Definition: Tooling.cpp:596
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
std::function< CommandLineArguments(const CommandLineArguments &, StringRef Filename)> ArgumentsAdjuster
A prototype of a command line adjuster.
std::string getAbsolutePath(StringRef File)
Returns the absolute path of File, by prepending it with the current directory if File is not absolut...
Definition: Tooling.cpp:240
JobList - A sequence of jobs to perform.
Definition: Job.h:171
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, CrashReportInfo *CrashInfo=nullptr) const
Definition: Job.cpp:435
ToolInvocation(std::vector< std::string > CommandLine, std::unique_ptr< FrontendAction > FAction, FileManager *Files, std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >())
Create a tool invocation.
Definition: Tooling.cpp:295
void addTargetAndModeForProgramName(std::vector< std::string > &CommandLine, StringRef InvokedAs)
Changes CommandLine to contain implicit flags that would have been defined had the compiler driver be...
Definition: Tooling.cpp:244
void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer)
Set a DiagnosticConsumer to use during parsing.
Definition: Tooling.h:262
Interface for compilation databases.
#define false
Definition: stdbool.h:17
static const llvm::opt::ArgStringList * getCC1Arguments(DiagnosticsEngine *Diagnostics, driver::Compilation *Compilation)
Retrieves the clang CC1 specific flags out of the compilation&#39;s jobs.
Definition: Tooling.cpp:89
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler&#39;s CompilerInvocation object...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
FileSystemOptions & getFileSystemOpts()
Returns the current file system options.
Definition: FileManager.h:352
Specifies the working directory and command of a compilation.
Options for controlling the compiler diagnostics engine.
bool runToolOnCode(std::unique_ptr< FrontendAction > ToolAction, const Twine &Code, const Twine &FileName="input.cc", std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >())
Runs (and deletes) the tool on &#39;Code&#39; with the -fsyntax-only flag.
Definition: Tooling.cpp:154
std::unique_ptr< ASTUnit > buildASTFromCodeWithArgs(StringRef Code, const std::vector< std::string > &Args, StringRef FileName="input.cc", StringRef ToolName="clang-tool", std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >(), ArgumentsAdjuster Adjuster=getClangStripDependencyFileAdjuster())
Builds an AST for &#39;Code&#39; with additional flags.
Definition: Tooling.cpp:619
iterator begin()
Definition: Job.h:195
bool runToolOnCodeWithArgs(std::unique_ptr< FrontendAction > ToolAction, const Twine &Code, const std::vector< std::string > &Args, const Twine &FileName="input.cc", const Twine &ToolName="clang-tool", std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >(), const FileContentMappings &VirtualMappedFiles=FileContentMappings())
Runs (and deletes) the tool on &#39;Code&#39; with the -fsyntax-only flag and with additional other flags...
Definition: Tooling.cpp:198
void setTitle(std::string Value)
Definition: Driver.h:316
int run(ToolAction *Action)
Runs an action over all files specified in the command line.
Definition: Tooling.cpp:448
void mapVirtualFile(StringRef FilePath, StringRef Content)
Map a virtual file to be used while running the tool.
Definition: Tooling.cpp:424
std::unique_ptr< ASTUnit > buildASTFromCode(StringRef Code, StringRef FileName="input.cc", std::shared_ptr< PCHContainerOperations > PCHContainerOps=std::make_shared< PCHContainerOperations >())
Builds an AST for &#39;Code&#39;.
Definition: Tooling.cpp:613
Utility to run a FrontendAction in a single clang invocation.
Definition: Tooling.h:230
Dataflow Directional Tag Classes.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
Definition: FileManager.cpp:68
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char *> CommandLineArgs, DiagnosticsEngine &Diags)
Create a compiler invocation from a list of input options.
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.
ActionList & getActions()
Definition: Compilation.h:190
CompilerInvocation * newInvocation(DiagnosticsEngine *Diagnostics, const llvm::opt::ArgStringList &CC1Args)
Creates a CompilerInvocation.
Definition: Tooling.cpp:144
size_type size() const
Definition: Job.h:194
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
Defines the clang::FileSystemOptions interface.
std::vector< std::string > CommandLine
The command line that was executed.
ArgumentsAdjuster getClangSyntaxOnlyAdjuster()
Gets an argument adjuster that converts input command line arguments to the "syntax check only" varia...
Keeps track of options that affect how file operations are performed.
void setInvocation(std::shared_ptr< CompilerInvocation > Value)
setInvocation - Replace the current invocation.
bool runInvocation(std::shared_ptr< CompilerInvocation > Invocation, FileManager *Files, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer) override
Invokes the compiler with a FrontendAction created by create().
Definition: Tooling.cpp:376
void setRestoreWorkingDir(bool RestoreCWD)
Sets whether working directory should be restored after calling run().
Definition: Tooling.cpp:601
Defines the Diagnostic IDs-related interfaces.
void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster)
Append a command line arguments adjuster to the adjuster chain.
Definition: Tooling.cpp:428
#define true
Definition: stdbool.h:16
void mapVirtualFile(StringRef FilePath, StringRef Content)
Map a virtual file to be used while running the tool.
Definition: Tooling.cpp:309
llvm::vfs::FileSystem & getVirtualFileSystem() const
Definition: FileManager.h:355
virtual bool runInvocation(std::shared_ptr< CompilerInvocation > Invocation, FileManager *Files, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagConsumer)=0
Perform an action for an invocation.
std::vector< std::pair< std::string, std::string > > FileContentMappings
The first part of the pair is the filename, the second part the file-content.
Definition: Tooling.h:164
virtual std::vector< CompileCommand > getCompileCommands(StringRef FilePath) const =0
Returns all compile commands in which the specified file was compiled.