ClangSrcLocDump.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. //===- ClangSrcLocDump.cpp ------------------------------------*- C++ -*---===//
  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. #include "clang/Basic/Diagnostic.h"
  9. #include "clang/Driver/Compilation.h"
  10. #include "clang/Driver/Driver.h"
  11. #include "clang/Driver/Job.h"
  12. #include "clang/Driver/Options.h"
  13. #include "clang/Driver/Tool.h"
  14. #include "clang/Frontend/CompilerInstance.h"
  15. #include "clang/Frontend/TextDiagnosticPrinter.h"
  16. #include "clang/Lex/PreprocessorOptions.h"
  17. #include "clang/Tooling/Tooling.h"
  18. #include "llvm/Option/ArgList.h"
  19. #include "llvm/Support/CommandLine.h"
  20. #include "llvm/Support/Host.h"
  21. #include "llvm/Support/JSON.h"
  22. #include "ASTSrcLocProcessor.h"
  23. using namespace clang::tooling;
  24. using namespace clang;
  25. using namespace llvm;
  26. static cl::list<std::string> IncludeDirectories(
  27. "I", cl::desc("Include directories to use while compiling"),
  28. cl::value_desc("directory"), cl::Required, cl::OneOrMore, cl::Prefix);
  29. static cl::opt<bool>
  30. SkipProcessing("skip-processing",
  31. cl::desc("Avoid processing the AST header file"),
  32. cl::Required, cl::value_desc("bool"));
  33. static cl::opt<std::string> JsonOutputPath("json-output-path",
  34. cl::desc("json output path"),
  35. cl::Required,
  36. cl::value_desc("path"));
  37. class ASTSrcLocGenerationAction : public clang::ASTFrontendAction {
  38. public:
  39. ASTSrcLocGenerationAction() : Processor(JsonOutputPath) {}
  40. void ExecuteAction() override {
  41. clang::ASTFrontendAction::ExecuteAction();
  42. if (getCompilerInstance().getDiagnostics().getNumErrors() > 0)
  43. Processor.generateEmpty();
  44. else
  45. Processor.generate();
  46. }
  47. std::unique_ptr<clang::ASTConsumer>
  48. CreateASTConsumer(clang::CompilerInstance &Compiler,
  49. llvm::StringRef File) override {
  50. return Processor.createASTConsumer(Compiler, File);
  51. }
  52. private:
  53. ASTSrcLocProcessor Processor;
  54. };
  55. static const char Filename[] = "ASTTU.cpp";
  56. int main(int argc, const char **argv) {
  57. cl::ParseCommandLineOptions(argc, argv);
  58. if (SkipProcessing) {
  59. std::error_code EC;
  60. llvm::raw_fd_ostream JsonOut(JsonOutputPath, EC, llvm::sys::fs::OF_Text);
  61. if (EC)
  62. return 1;
  63. JsonOut << formatv("{0:2}", llvm::json::Value(llvm::json::Object()));
  64. return 0;
  65. }
  66. std::vector<std::string> Args;
  67. Args.push_back("-cc1");
  68. llvm::transform(IncludeDirectories, std::back_inserter(Args),
  69. [](const std::string &IncDir) { return "-I" + IncDir; });
  70. Args.push_back("-fsyntax-only");
  71. Args.push_back(Filename);
  72. std::vector<const char *> Argv(Args.size(), nullptr);
  73. llvm::transform(Args, Argv.begin(),
  74. [](const std::string &Arg) { return Arg.c_str(); });
  75. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
  76. CreateAndPopulateDiagOpts(Argv);
  77. // Don't output diagnostics, because common scenarios such as
  78. // cross-compiling fail with diagnostics. This is not fatal, but
  79. // just causes attempts to use the introspection API to return no data.
  80. TextDiagnosticPrinter DiagnosticPrinter(llvm::nulls(), &*DiagOpts);
  81. DiagnosticsEngine Diagnostics(
  82. IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
  83. &DiagnosticPrinter, false);
  84. auto *OFS = new llvm::vfs::OverlayFileSystem(vfs::getRealFileSystem());
  85. auto *MemFS = new llvm::vfs::InMemoryFileSystem();
  86. OFS->pushOverlay(MemFS);
  87. MemFS->addFile(Filename, 0,
  88. MemoryBuffer::getMemBuffer("#include \"clang/AST/AST.h\"\n"));
  89. auto Files = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions(), OFS);
  90. auto Driver = std::make_unique<driver::Driver>(
  91. "clang", llvm::sys::getDefaultTargetTriple(), Diagnostics,
  92. "ast-api-dump-tool", OFS);
  93. std::unique_ptr<clang::driver::Compilation> Comp(
  94. Driver->BuildCompilation(llvm::ArrayRef(Argv)));
  95. if (!Comp)
  96. return 1;
  97. const auto &Jobs = Comp->getJobs();
  98. if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
  99. SmallString<256> error_msg;
  100. llvm::raw_svector_ostream error_stream(error_msg);
  101. Jobs.Print(error_stream, "; ", true);
  102. return 1;
  103. }
  104. const auto &Cmd = cast<driver::Command>(*Jobs.begin());
  105. const llvm::opt::ArgStringList &CC1Args = Cmd.getArguments();
  106. auto Invocation = std::make_unique<CompilerInvocation>();
  107. CompilerInvocation::CreateFromArgs(*Invocation, CC1Args, Diagnostics);
  108. CompilerInstance Compiler(std::make_shared<clang::PCHContainerOperations>());
  109. Compiler.setInvocation(std::move(Invocation));
  110. Compiler.createDiagnostics(&DiagnosticPrinter, false);
  111. if (!Compiler.hasDiagnostics())
  112. return 1;
  113. // Suppress "2 errors generated" or similar messages
  114. Compiler.getDiagnosticOpts().ShowCarets = false;
  115. Compiler.createSourceManager(*Files);
  116. Compiler.setFileManager(Files.get());
  117. ASTSrcLocGenerationAction ScopedToolAction;
  118. Compiler.ExecuteAction(ScopedToolAction);
  119. Files->clearStatCache();
  120. return 0;
  121. }