blob: 804745d2859907aec257860236e6247e513bb89f [file] [log] [blame]
Fangrui Song524b3c12019-03-01 06:49:51 +00001//===- ClangExtDefMapGen.cpp -----------------------------------------------===//
Gabor Horvathe350b0a2017-09-22 11:11:01 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Gabor Horvathe350b0a2017-09-22 11:11:01 +00006//
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"
Gabor Horvathe350b0a2017-09-22 11:11:01 +000016#include "clang/Basic/SourceManager.h"
Gabor Horvathe350b0a2017-09-22 11:11:01 +000017#include "clang/CrossTU/CrossTranslationUnit.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Frontend/FrontendActions.h"
Gabor Horvathe350b0a2017-09-22 11:11:01 +000020#include "clang/Tooling/CommonOptionsParser.h"
21#include "clang/Tooling/Tooling.h"
22#include "llvm/Support/CommandLine.h"
Gabor Horvathe350b0a2017-09-22 11:11:01 +000023#include "llvm/Support/Signals.h"
24#include <sstream>
25#include <string>
Gabor Horvathe350b0a2017-09-22 11:11:01 +000026
27using namespace llvm;
28using namespace clang;
29using namespace clang::cross_tu;
30using namespace clang::tooling;
31
Rafael Stahl8c487052019-01-10 17:44:04 +000032static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options");
Gabor Horvathe350b0a2017-09-22 11:11:01 +000033
Rafael Stahl8c487052019-01-10 17:44:04 +000034class MapExtDefNamesConsumer : public ASTConsumer {
Gabor Horvathe350b0a2017-09-22 11:11:01 +000035public:
Rafael Stahl8c487052019-01-10 17:44:04 +000036 MapExtDefNamesConsumer(ASTContext &Context)
Rafael Stahl850361f2019-04-23 11:04:41 +000037 : Ctx(Context), SM(Context.getSourceManager()) {}
Gabor Horvathe350b0a2017-09-22 11:11:01 +000038
Rafael Stahl8c487052019-01-10 17:44:04 +000039 ~MapExtDefNamesConsumer() {
Gabor Horvathe350b0a2017-09-22 11:11:01 +000040 // Flush results to standard output.
41 llvm::outs() << createCrossTUIndexString(Index);
42 }
43
Rafael Stahl850361f2019-04-23 11:04:41 +000044 void HandleTranslationUnit(ASTContext &Context) override {
45 handleDecl(Context.getTranslationUnitDecl());
Gabor Horvathe350b0a2017-09-22 11:11:01 +000046 }
47
48private:
49 void handleDecl(const Decl *D);
Rafael Stahl850361f2019-04-23 11:04:41 +000050 void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart);
Gabor Horvathe350b0a2017-09-22 11:11:01 +000051
Rafael Stahl850361f2019-04-23 11:04:41 +000052 ASTContext &Ctx;
Gabor Horvath9c0fdc12018-11-02 11:22:22 +000053 SourceManager &SM;
Gabor Horvathe350b0a2017-09-22 11:11:01 +000054 llvm::StringMap<std::string> Index;
55 std::string CurrentFileName;
56};
57
Rafael Stahl8c487052019-01-10 17:44:04 +000058void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
Gabor Horvathe350b0a2017-09-22 11:11:01 +000059 if (!D)
60 return;
61
62 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
Rafael Stahl850361f2019-04-23 11:04:41 +000063 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());
Gabor Horvathe350b0a2017-09-22 11:11:01 +000070 }
71
72 if (const auto *DC = dyn_cast<DeclContext>(D))
73 for (const Decl *D : DC->decls())
74 handleDecl(D);
75}
76
Rafael Stahl850361f2019-04-23 11:04:41 +000077void 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 default:
94 break;
95 }
96}
97
Rafael Stahl8c487052019-01-10 17:44:04 +000098class MapExtDefNamesAction : public ASTFrontendAction {
Gabor Horvathe350b0a2017-09-22 11:11:01 +000099protected:
100 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
101 llvm::StringRef) {
Rafael Stahl8c487052019-01-10 17:44:04 +0000102 return llvm::make_unique<MapExtDefNamesConsumer>(CI.getASTContext());
Gabor Horvathe350b0a2017-09-22 11:11:01 +0000103 }
104};
105
106static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
107
108int main(int argc, const char **argv) {
109 // Print a stack trace if we signal out.
110 sys::PrintStackTraceOnErrorSignal(argv[0], false);
111 PrettyStackTraceProgram X(argc, argv);
112
113 const char *Overview = "\nThis tool collects the USR name and location "
Rafael Stahl8c487052019-01-10 17:44:04 +0000114 "of external definitions in the source files "
Gabor Horvathe350b0a2017-09-22 11:11:01 +0000115 "(excluding headers).\n";
Rafael Stahl8c487052019-01-10 17:44:04 +0000116 CommonOptionsParser OptionsParser(argc, argv, ClangExtDefMapGenCategory,
Gabor Horvathe350b0a2017-09-22 11:11:01 +0000117 cl::ZeroOrMore, Overview);
118
119 ClangTool Tool(OptionsParser.getCompilations(),
120 OptionsParser.getSourcePathList());
Gabor Horvath9c0fdc12018-11-02 11:22:22 +0000121
Rafael Stahl8c487052019-01-10 17:44:04 +0000122 return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
Gabor Horvathe350b0a2017-09-22 11:11:01 +0000123}