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