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