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 : SM(Context.getSourceManager()) {} 38 39 ~MapExtDefNamesConsumer() { 40 // Flush results to standard output. 41 llvm::outs() << createCrossTUIndexString(Index); 42 } 43 44 void HandleTranslationUnit(ASTContext &Ctx) override { 45 handleDecl(Ctx.getTranslationUnitDecl()); 46 } 47 48 private: 49 void handleDecl(const Decl *D); 50 51 SourceManager &SM; 52 llvm::StringMap<std::string> Index; 53 std::string CurrentFileName; 54 }; 55 56 void MapExtDefNamesConsumer::handleDecl(const Decl *D) { 57 if (!D) 58 return; 59 60 if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 61 if (FD->isThisDeclarationADefinition()) { 62 if (const Stmt *Body = FD->getBody()) { 63 if (CurrentFileName.empty()) { 64 CurrentFileName = 65 SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName(); 66 if (CurrentFileName.empty()) 67 CurrentFileName = "invalid_file"; 68 } 69 70 switch (FD->getLinkageInternal()) { 71 case ExternalLinkage: 72 case VisibleNoLinkage: 73 case UniqueExternalLinkage: 74 if (SM.isInMainFile(Body->getBeginLoc())) { 75 std::string LookupName = 76 CrossTranslationUnitContext::getLookupName(FD); 77 Index[LookupName] = CurrentFileName; 78 } 79 break; 80 default: 81 break; 82 } 83 } 84 } 85 } 86 87 if (const auto *DC = dyn_cast<DeclContext>(D)) 88 for (const Decl *D : DC->decls()) 89 handleDecl(D); 90 } 91 92 class MapExtDefNamesAction : public ASTFrontendAction { 93 protected: 94 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 95 llvm::StringRef) { 96 return llvm::make_unique<MapExtDefNamesConsumer>(CI.getASTContext()); 97 } 98 }; 99 100 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); 101 102 int main(int argc, const char **argv) { 103 // Print a stack trace if we signal out. 104 sys::PrintStackTraceOnErrorSignal(argv[0], false); 105 PrettyStackTraceProgram X(argc, argv); 106 107 const char *Overview = "\nThis tool collects the USR name and location " 108 "of external definitions in the source files " 109 "(excluding headers).\n"; 110 CommonOptionsParser OptionsParser(argc, argv, ClangExtDefMapGenCategory, 111 cl::ZeroOrMore, Overview); 112 113 ClangTool Tool(OptionsParser.getCompilations(), 114 OptionsParser.getSourcePathList()); 115 116 return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get()); 117 } 118