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:
MapExtDefNamesConsumer(ASTContext & Context)36 MapExtDefNamesConsumer(ASTContext &Context)
37 : Ctx(Context), SM(Context.getSourceManager()) {}
38
~MapExtDefNamesConsumer()39 ~MapExtDefNamesConsumer() {
40 // Flush results to standard output.
41 llvm::outs() << createCrossTUIndexString(Index);
42 }
43
HandleTranslationUnit(ASTContext & Context)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
handleDecl(const Decl * D)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
addIfInMain(const DeclaratorDecl * DD,SourceLocation defStart)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:
CreateASTConsumer(CompilerInstance & CI,llvm::StringRef)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
main(int argc,const char ** argv)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