xref: /netbsd-src/external/apache2/llvm/dist/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===- ClangExtDefMapGen.cpp -----------------------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===--------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Clang tool which creates a list of defined functions and the files in which
107330f729Sjoerg // they are defined.
117330f729Sjoerg //
127330f729Sjoerg //===--------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "clang/AST/ASTConsumer.h"
157330f729Sjoerg #include "clang/AST/ASTContext.h"
167330f729Sjoerg #include "clang/Basic/SourceManager.h"
177330f729Sjoerg #include "clang/CrossTU/CrossTranslationUnit.h"
187330f729Sjoerg #include "clang/Frontend/CompilerInstance.h"
197330f729Sjoerg #include "clang/Frontend/FrontendActions.h"
207330f729Sjoerg #include "clang/Tooling/CommonOptionsParser.h"
217330f729Sjoerg #include "clang/Tooling/Tooling.h"
227330f729Sjoerg #include "llvm/Support/CommandLine.h"
237330f729Sjoerg #include "llvm/Support/Signals.h"
247330f729Sjoerg #include <sstream>
257330f729Sjoerg #include <string>
267330f729Sjoerg 
277330f729Sjoerg using namespace llvm;
287330f729Sjoerg using namespace clang;
297330f729Sjoerg using namespace clang::cross_tu;
307330f729Sjoerg using namespace clang::tooling;
317330f729Sjoerg 
327330f729Sjoerg static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options");
337330f729Sjoerg 
347330f729Sjoerg class MapExtDefNamesConsumer : public ASTConsumer {
357330f729Sjoerg public:
MapExtDefNamesConsumer(ASTContext & Context)367330f729Sjoerg   MapExtDefNamesConsumer(ASTContext &Context)
377330f729Sjoerg       : Ctx(Context), SM(Context.getSourceManager()) {}
387330f729Sjoerg 
~MapExtDefNamesConsumer()397330f729Sjoerg   ~MapExtDefNamesConsumer() {
407330f729Sjoerg     // Flush results to standard output.
417330f729Sjoerg     llvm::outs() << createCrossTUIndexString(Index);
427330f729Sjoerg   }
437330f729Sjoerg 
HandleTranslationUnit(ASTContext & Context)447330f729Sjoerg   void HandleTranslationUnit(ASTContext &Context) override {
457330f729Sjoerg     handleDecl(Context.getTranslationUnitDecl());
467330f729Sjoerg   }
477330f729Sjoerg 
487330f729Sjoerg private:
497330f729Sjoerg   void handleDecl(const Decl *D);
507330f729Sjoerg   void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart);
517330f729Sjoerg 
527330f729Sjoerg   ASTContext &Ctx;
537330f729Sjoerg   SourceManager &SM;
547330f729Sjoerg   llvm::StringMap<std::string> Index;
557330f729Sjoerg   std::string CurrentFileName;
567330f729Sjoerg };
577330f729Sjoerg 
handleDecl(const Decl * D)587330f729Sjoerg void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
597330f729Sjoerg   if (!D)
607330f729Sjoerg     return;
617330f729Sjoerg 
627330f729Sjoerg   if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
637330f729Sjoerg     if (FD->isThisDeclarationADefinition())
647330f729Sjoerg       if (const Stmt *Body = FD->getBody())
657330f729Sjoerg         addIfInMain(FD, Body->getBeginLoc());
667330f729Sjoerg   } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
677330f729Sjoerg     if (cross_tu::containsConst(VD, Ctx) && VD->hasInit())
687330f729Sjoerg       if (const Expr *Init = VD->getInit())
697330f729Sjoerg         addIfInMain(VD, Init->getBeginLoc());
707330f729Sjoerg   }
717330f729Sjoerg 
727330f729Sjoerg   if (const auto *DC = dyn_cast<DeclContext>(D))
737330f729Sjoerg     for (const Decl *D : DC->decls())
747330f729Sjoerg       handleDecl(D);
757330f729Sjoerg }
767330f729Sjoerg 
addIfInMain(const DeclaratorDecl * DD,SourceLocation defStart)777330f729Sjoerg void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,
787330f729Sjoerg                                          SourceLocation defStart) {
797330f729Sjoerg   llvm::Optional<std::string> LookupName =
807330f729Sjoerg       CrossTranslationUnitContext::getLookupName(DD);
817330f729Sjoerg   if (!LookupName)
827330f729Sjoerg     return;
837330f729Sjoerg   assert(!LookupName->empty() && "Lookup name should be non-empty.");
847330f729Sjoerg 
857330f729Sjoerg   if (CurrentFileName.empty()) {
86*e038c9c4Sjoerg     CurrentFileName = std::string(
87*e038c9c4Sjoerg         SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName());
887330f729Sjoerg     if (CurrentFileName.empty())
897330f729Sjoerg       CurrentFileName = "invalid_file";
907330f729Sjoerg   }
917330f729Sjoerg 
927330f729Sjoerg   switch (DD->getLinkageInternal()) {
937330f729Sjoerg   case ExternalLinkage:
947330f729Sjoerg   case VisibleNoLinkage:
957330f729Sjoerg   case UniqueExternalLinkage:
967330f729Sjoerg     if (SM.isInMainFile(defStart))
977330f729Sjoerg       Index[*LookupName] = CurrentFileName;
987330f729Sjoerg     break;
997330f729Sjoerg   default:
1007330f729Sjoerg     break;
1017330f729Sjoerg   }
1027330f729Sjoerg }
1037330f729Sjoerg 
1047330f729Sjoerg class MapExtDefNamesAction : public ASTFrontendAction {
1057330f729Sjoerg protected:
CreateASTConsumer(CompilerInstance & CI,llvm::StringRef)1067330f729Sjoerg   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
107*e038c9c4Sjoerg                                                  llvm::StringRef) override {
1087330f729Sjoerg     return std::make_unique<MapExtDefNamesConsumer>(CI.getASTContext());
1097330f729Sjoerg   }
1107330f729Sjoerg };
1117330f729Sjoerg 
1127330f729Sjoerg static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
1137330f729Sjoerg 
main(int argc,const char ** argv)1147330f729Sjoerg int main(int argc, const char **argv) {
1157330f729Sjoerg   // Print a stack trace if we signal out.
1167330f729Sjoerg   sys::PrintStackTraceOnErrorSignal(argv[0], false);
1177330f729Sjoerg   PrettyStackTraceProgram X(argc, argv);
1187330f729Sjoerg 
1197330f729Sjoerg   const char *Overview = "\nThis tool collects the USR name and location "
1207330f729Sjoerg                          "of external definitions in the source files "
1217330f729Sjoerg                          "(excluding headers).\n";
122*e038c9c4Sjoerg   auto ExpectedParser = CommonOptionsParser::create(
123*e038c9c4Sjoerg       argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview);
124*e038c9c4Sjoerg   if (!ExpectedParser) {
125*e038c9c4Sjoerg     llvm::errs() << ExpectedParser.takeError();
126*e038c9c4Sjoerg     return 1;
127*e038c9c4Sjoerg   }
128*e038c9c4Sjoerg   CommonOptionsParser &OptionsParser = ExpectedParser.get();
1297330f729Sjoerg 
1307330f729Sjoerg   ClangTool Tool(OptionsParser.getCompilations(),
1317330f729Sjoerg                  OptionsParser.getSourcePathList());
1327330f729Sjoerg 
1337330f729Sjoerg   return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());
1347330f729Sjoerg }
135