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   std::string LookupName = CrossTranslationUnitContext::getLookupName(DD);
80   if (CurrentFileName.empty()) {
81     CurrentFileName =
82         SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName();
83     if (CurrentFileName.empty())
84       CurrentFileName = "invalid_file";
85   }
86 
87   switch (DD->getLinkageInternal()) {
88   case ExternalLinkage:
89   case VisibleNoLinkage:
90   case UniqueExternalLinkage:
91     if (SM.isInMainFile(defStart))
92       Index[LookupName] = CurrentFileName;
93     break;
94   default:
95     break;
96   }
97 }
98 
99 class MapExtDefNamesAction : public ASTFrontendAction {
100 protected:
101   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
102                                                  llvm::StringRef) {
103     return llvm::make_unique<MapExtDefNamesConsumer>(CI.getASTContext());
104   }
105 };
106 
107 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
108 
109 int main(int argc, const char **argv) {
110   // Print a stack trace if we signal out.
111   sys::PrintStackTraceOnErrorSignal(argv[0], false);
112   PrettyStackTraceProgram X(argc, argv);
113 
114   const char *Overview = "\nThis tool collects the USR name and location "
115                          "of external definitions in the source files "
116                          "(excluding headers).\n";
117   CommonOptionsParser OptionsParser(argc, argv, ClangExtDefMapGenCategory,
118                                     cl::ZeroOrMore, Overview);
119 
120   ClangTool Tool(OptionsParser.getCompilations(),
121                  OptionsParser.getSourcePathList());
122 
123   return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
124 }
125