brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · 6d8f86b Raw
228 lines · cpp
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-exception6//7//===--------------------------------------------------------------------===//8//9// Clang tool which creates a list of defined functions and the files in which10// they are defined.11//12//===--------------------------------------------------------------------===//13 14#include "clang/AST/ASTConsumer.h"15#include "clang/AST/ASTContext.h"16#include "clang/Basic/DiagnosticOptions.h"17#include "clang/Basic/SourceManager.h"18#include "clang/CrossTU/CrossTranslationUnit.h"19#include "clang/Frontend/CompilerInstance.h"20#include "clang/Frontend/FrontendActions.h"21#include "clang/Frontend/TextDiagnosticPrinter.h"22#include "clang/Tooling/CommonOptionsParser.h"23#include "clang/Tooling/Tooling.h"24#include "llvm/Support/CommandLine.h"25#include "llvm/Support/Signals.h"26#include "llvm/Support/TargetSelect.h"27#include <optional>28#include <sstream>29#include <string>30 31using namespace llvm;32using namespace clang;33using namespace clang::cross_tu;34using namespace clang::tooling;35 36static cl::OptionCategory37    ClangExtDefMapGenCategory("clang-extdefmapgen options");38 39class MapExtDefNamesConsumer : public ASTConsumer {40public:41  MapExtDefNamesConsumer(ASTContext &Context,42                         StringRef astFilePath = StringRef())43      : Ctx(Context), SM(Context.getSourceManager()) {44    CurrentFileName = astFilePath.str();45  }46 47  ~MapExtDefNamesConsumer() {48    // Flush results to standard output.49    llvm::outs() << createCrossTUIndexString(Index);50  }51 52  void HandleTranslationUnit(ASTContext &Context) override {53    handleDecl(Context.getTranslationUnitDecl());54  }55 56private:57  void handleDecl(const Decl *D);58  void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart);59 60  ASTContext &Ctx;61  SourceManager &SM;62  llvm::StringMap<std::string> Index;63  std::string CurrentFileName;64};65 66void MapExtDefNamesConsumer::handleDecl(const Decl *D) {67  if (!D)68    return;69 70  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {71    if (FD->isThisDeclarationADefinition())72      if (const Stmt *Body = FD->getBody())73        addIfInMain(FD, Body->getBeginLoc());74  } else if (const auto *VD = dyn_cast<VarDecl>(D)) {75    if (cross_tu::shouldImport(VD, Ctx) && VD->hasInit())76      if (const Expr *Init = VD->getInit())77        addIfInMain(VD, Init->getBeginLoc());78  }79 80  if (const auto *DC = dyn_cast<DeclContext>(D))81    for (const Decl *D : DC->decls())82      handleDecl(D);83}84 85void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,86                                         SourceLocation defStart) {87  std::optional<std::string> LookupName =88      CrossTranslationUnitContext::getLookupName(DD);89  if (!LookupName)90    return;91  assert(!LookupName->empty() && "Lookup name should be non-empty.");92 93  if (CurrentFileName.empty()) {94    CurrentFileName = std::string(95        SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName());96    if (CurrentFileName.empty())97      CurrentFileName = "invalid_file";98  }99 100  switch (DD->getLinkageInternal()) {101  case Linkage::External:102  case Linkage::VisibleNone:103  case Linkage::UniqueExternal:104    if (SM.isInMainFile(defStart))105      Index[*LookupName] = CurrentFileName;106    break;107  case Linkage::Invalid:108    llvm_unreachable("Linkage has not been computed!");109  default:110    break;111  }112}113 114class MapExtDefNamesAction : public ASTFrontendAction {115protected:116  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,117                                                 llvm::StringRef) override {118    return std::make_unique<MapExtDefNamesConsumer>(CI.getASTContext());119  }120};121 122static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);123 124static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;125 126IntrusiveRefCntPtr<DiagnosticsEngine>127GetDiagnosticsEngine(DiagnosticOptions &DiagOpts) {128  if (Diags) {129    // Call reset to make sure we don't mix errors130    Diags->Reset(false);131    return Diags;132  }133 134  TextDiagnosticPrinter *DiagClient =135      new TextDiagnosticPrinter(llvm::errs(), DiagOpts);136  DiagClient->setPrefix("clang-extdef-mappping");137 138  auto DiagEngine = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(139      DiagnosticIDs::create(), DiagOpts, DiagClient);140  Diags.swap(DiagEngine);141 142  // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile143  Diags->Retain();144  return Diags;145}146 147static CompilerInstance *CI = nullptr;148 149static bool HandleAST(StringRef AstPath) {150 151  if (!CI)152    CI = new CompilerInstance();153 154  auto DiagOpts = std::make_shared<DiagnosticOptions>();155  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine =156      GetDiagnosticsEngine(*DiagOpts);157 158  std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(159      AstPath, CI->getPCHContainerOperations()->getRawReader(),160      ASTUnit::LoadASTOnly, CI->getVirtualFileSystemPtr(), DiagOpts, DiagEngine,161      CI->getFileSystemOpts(), CI->getHeaderSearchOpts());162 163  if (!Unit)164    return false;165 166  FileManager FM(CI->getFileSystemOpts());167  SmallString<128> AbsPath(AstPath);168  FM.makeAbsolutePath(AbsPath);169 170  MapExtDefNamesConsumer Consumer =171      MapExtDefNamesConsumer(Unit->getASTContext(), AbsPath);172  Consumer.HandleTranslationUnit(Unit->getASTContext());173 174  return true;175}176 177static int HandleFiles(ArrayRef<std::string> SourceFiles,178                       CompilationDatabase &compilations) {179  std::vector<std::string> SourcesToBeParsed;180 181  // Loop over all input files, if they are pre-compiled AST182  // process them directly in HandleAST, otherwise put them183  // on a list for ClangTool to handle.184  for (StringRef Src : SourceFiles) {185    if (Src.ends_with(".ast")) {186      if (!HandleAST(Src)) {187        return 1;188      }189    } else {190      SourcesToBeParsed.push_back(Src.str());191    }192  }193 194  if (!SourcesToBeParsed.empty()) {195    ClangTool Tool(compilations, SourcesToBeParsed);196    return Tool.run(newFrontendActionFactory<MapExtDefNamesAction>().get());197  }198 199  return 0;200}201 202int main(int argc, const char **argv) {203  // Print a stack trace if we signal out.204  sys::PrintStackTraceOnErrorSignal(argv[0], false);205  PrettyStackTraceProgram X(argc, argv);206 207  const char *Overview = "\nThis tool collects the USR name and location "208                         "of external definitions in the source files "209                         "(excluding headers).\n"210                         "Input can be either source files that are compiled "211                         "with compile database or .ast files that are "212                         "created from clang's -emit-ast option.\n";213  auto ExpectedParser = CommonOptionsParser::create(214      argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview);215  if (!ExpectedParser) {216    llvm::errs() << ExpectedParser.takeError();217    return 1;218  }219  CommonOptionsParser &OptionsParser = ExpectedParser.get();220 221  llvm::InitializeAllTargetInfos();222  llvm::InitializeAllTargetMCs();223  llvm::InitializeAllAsmParsers();224 225  return HandleFiles(OptionsParser.getSourcePathList(),226                     OptionsParser.getCompilations());227}228