1 //===- ClangExtDefMapGen.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 // Clang tool which creates a list of defined functions and the files in which 10 // they are defined. 11 // 12 //===--------------------------------------------------------------------===// 13 14 #include "clang/AST/ASTConsumer.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/Basic/SourceManager.h" 17 #include "clang/CrossTU/CrossTranslationUnit.h" 18 #include "clang/Frontend/CompilerInstance.h" 19 #include "clang/Frontend/FrontendActions.h" 20 #include "clang/Tooling/CommonOptionsParser.h" 21 #include "clang/Tooling/Tooling.h" 22 #include "llvm/Support/CommandLine.h" 23 #include "llvm/Support/Signals.h" 24 #include <sstream> 25 #include <string> 26 27 using namespace llvm; 28 using namespace clang; 29 using namespace clang::cross_tu; 30 using namespace clang::tooling; 31 32 static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options"); 33 34 class MapExtDefNamesConsumer : public ASTConsumer { 35 public: 36 MapExtDefNamesConsumer(ASTContext &Context) 37 : Ctx(Context), SM(Context.getSourceManager()) {} 38 39 ~MapExtDefNamesConsumer() { 40 // Flush results to standard output. 41 llvm::outs() << createCrossTUIndexString(Index); 42 } 43 44 void HandleTranslationUnit(ASTContext &Context) override { 45 handleDecl(Context.getTranslationUnitDecl()); 46 } 47 48 private: 49 void handleDecl(const Decl *D); 50 void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart); 51 52 ASTContext &Ctx; 53 SourceManager &SM; 54 llvm::StringMap<std::string> Index; 55 std::string CurrentFileName; 56 }; 57 58 void MapExtDefNamesConsumer::handleDecl(const Decl *D) { 59 if (!D) 60 return; 61 62 if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 63 if (FD->isThisDeclarationADefinition()) 64 if (const Stmt *Body = FD->getBody()) 65 addIfInMain(FD, Body->getBeginLoc()); 66 } else if (const auto *VD = dyn_cast<VarDecl>(D)) { 67 if (cross_tu::containsConst(VD, Ctx) && VD->hasInit()) 68 if (const Expr *Init = VD->getInit()) 69 addIfInMain(VD, Init->getBeginLoc()); 70 } 71 72 if (const auto *DC = dyn_cast<DeclContext>(D)) 73 for (const Decl *D : DC->decls()) 74 handleDecl(D); 75 } 76 77 void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD, 78 SourceLocation defStart) { 79 llvm::Optional<std::string> LookupName = 80 CrossTranslationUnitContext::getLookupName(DD); 81 if (!LookupName) 82 return; 83 assert(!LookupName->empty() && "Lookup name should be non-empty."); 84 85 if (CurrentFileName.empty()) { 86 CurrentFileName = std::string( 87 SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName()); 88 if (CurrentFileName.empty()) 89 CurrentFileName = "invalid_file"; 90 } 91 92 switch (DD->getLinkageInternal()) { 93 case ExternalLinkage: 94 case VisibleNoLinkage: 95 case UniqueExternalLinkage: 96 if (SM.isInMainFile(defStart)) 97 Index[*LookupName] = CurrentFileName; 98 break; 99 default: 100 break; 101 } 102 } 103 104 class MapExtDefNamesAction : public ASTFrontendAction { 105 protected: 106 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 107 llvm::StringRef) override { 108 return std::make_unique<MapExtDefNamesConsumer>(CI.getASTContext()); 109 } 110 }; 111 112 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 113 114 int main(int argc, const char **argv) { 115 // Print a stack trace if we signal out. 116 sys::PrintStackTraceOnErrorSignal(argv[0], false); 117 PrettyStackTraceProgram X(argc, argv); 118 119 const char *Overview = "\nThis tool collects the USR name and location " 120 "of external definitions in the source files " 121 "(excluding headers).\n"; 122 auto ExpectedParser = CommonOptionsParser::create( 123 argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview); 124 if (!ExpectedParser) { 125 llvm::errs() << ExpectedParser.takeError(); 126 return 1; 127 } 128 CommonOptionsParser &OptionsParser = ExpectedParser.get(); 129 130 ClangTool Tool(OptionsParser.getCompilations(), 131 OptionsParser.getSourcePathList()); 132 133 return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get()); 134 } 135