PrintFunctionNames.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //===- PrintFunctionNames.cpp ---------------------------------------------===//
  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. // Example clang plugin which simply prints the names of all the top-level decls
  10. // in the input file.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/Frontend/FrontendPluginRegistry.h"
  14. #include "clang/AST/AST.h"
  15. #include "clang/AST/ASTConsumer.h"
  16. #include "clang/AST/RecursiveASTVisitor.h"
  17. #include "clang/Frontend/CompilerInstance.h"
  18. #include "clang/Sema/Sema.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. using namespace clang;
  21. namespace {
  22. class PrintFunctionsConsumer : public ASTConsumer {
  23. CompilerInstance &Instance;
  24. std::set<std::string> ParsedTemplates;
  25. public:
  26. PrintFunctionsConsumer(CompilerInstance &Instance,
  27. std::set<std::string> ParsedTemplates)
  28. : Instance(Instance), ParsedTemplates(ParsedTemplates) {}
  29. bool HandleTopLevelDecl(DeclGroupRef DG) override {
  30. for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
  31. const Decl *D = *i;
  32. if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
  33. llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
  34. }
  35. return true;
  36. }
  37. void HandleTranslationUnit(ASTContext& context) override {
  38. if (!Instance.getLangOpts().DelayedTemplateParsing)
  39. return;
  40. // This demonstrates how to force instantiation of some templates in
  41. // -fdelayed-template-parsing mode. (Note: Doing this unconditionally for
  42. // all templates is similar to not using -fdelayed-template-parsig in the
  43. // first place.)
  44. // The advantage of doing this in HandleTranslationUnit() is that all
  45. // codegen (when using -add-plugin) is completely finished and this can't
  46. // affect the compiler output.
  47. struct Visitor : public RecursiveASTVisitor<Visitor> {
  48. const std::set<std::string> &ParsedTemplates;
  49. Visitor(const std::set<std::string> &ParsedTemplates)
  50. : ParsedTemplates(ParsedTemplates) {}
  51. bool VisitFunctionDecl(FunctionDecl *FD) {
  52. if (FD->isLateTemplateParsed() &&
  53. ParsedTemplates.count(FD->getNameAsString()))
  54. LateParsedDecls.insert(FD);
  55. return true;
  56. }
  57. std::set<FunctionDecl*> LateParsedDecls;
  58. } v(ParsedTemplates);
  59. v.TraverseDecl(context.getTranslationUnitDecl());
  60. clang::Sema &sema = Instance.getSema();
  61. for (const FunctionDecl *FD : v.LateParsedDecls) {
  62. clang::LateParsedTemplate &LPT =
  63. *sema.LateParsedTemplateMap.find(FD)->second;
  64. sema.LateTemplateParser(sema.OpaqueParser, LPT);
  65. llvm::errs() << "late-parsed-decl: \"" << FD->getNameAsString() << "\"\n";
  66. }
  67. }
  68. };
  69. class PrintFunctionNamesAction : public PluginASTAction {
  70. std::set<std::string> ParsedTemplates;
  71. protected:
  72. std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
  73. llvm::StringRef) override {
  74. return llvm::make_unique<PrintFunctionsConsumer>(CI, ParsedTemplates);
  75. }
  76. bool ParseArgs(const CompilerInstance &CI,
  77. const std::vector<std::string> &args) override {
  78. for (unsigned i = 0, e = args.size(); i != e; ++i) {
  79. llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
  80. // Example error handling.
  81. DiagnosticsEngine &D = CI.getDiagnostics();
  82. if (args[i] == "-an-error") {
  83. unsigned DiagID = D.getCustomDiagID(DiagnosticsEngine::Error,
  84. "invalid argument '%0'");
  85. D.Report(DiagID) << args[i];
  86. return false;
  87. } else if (args[i] == "-parse-template") {
  88. if (i + 1 >= e) {
  89. D.Report(D.getCustomDiagID(DiagnosticsEngine::Error,
  90. "missing -parse-template argument"));
  91. return false;
  92. }
  93. ++i;
  94. ParsedTemplates.insert(args[i]);
  95. }
  96. }
  97. if (!args.empty() && args[0] == "help")
  98. PrintHelp(llvm::errs());
  99. return true;
  100. }
  101. void PrintHelp(llvm::raw_ostream& ros) {
  102. ros << "Help for PrintFunctionNames plugin goes here\n";
  103. }
  104. };
  105. }
  106. static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
  107. X("print-fns", "print function names");