brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · 6bac717 Raw
159 lines · cpp
1//===-- FindAllSymbolsMain.cpp - find all symbols tool ----------*- C++ -*-===//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#include "FindAllSymbolsAction.h"10#include "STLPostfixHeaderMap.h"11#include "SymbolInfo.h"12#include "SymbolReporter.h"13#include "clang/ASTMatchers/ASTMatchFinder.h"14#include "clang/ASTMatchers/ASTMatchers.h"15#include "clang/Frontend/CompilerInstance.h"16#include "clang/Frontend/FrontendActions.h"17#include "clang/Lex/Preprocessor.h"18#include "clang/Tooling/CommonOptionsParser.h"19#include "clang/Tooling/Tooling.h"20#include "llvm/ADT/ArrayRef.h"21#include "llvm/ADT/SmallString.h"22#include "llvm/ADT/StringRef.h"23#include "llvm/Support/CommandLine.h"24#include "llvm/Support/FileSystem.h"25#include "llvm/Support/MemoryBuffer.h"26#include "llvm/Support/Path.h"27#include "llvm/Support/ThreadPool.h"28#include "llvm/Support/raw_ostream.h"29#include <map>30#include <mutex>31#include <set>32#include <string>33#include <system_error>34#include <vector>35 36using namespace clang::tooling;37using namespace llvm;38using SymbolInfo = clang::find_all_symbols::SymbolInfo;39 40// Apply a custom category to all command-line options so that they are the41// only ones displayed.42static cl::OptionCategory FindAllSymbolsCategory("find_all_symbols options");43 44// CommonOptionsParser declares HelpMessage with a description of the common45// command-line options related to the compilation database and input files.46// It's nice to have this help message in all tools.47static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);48 49// A help message for this specific tool can be added afterwards.50static cl::extrahelp MoreHelp("\nMore help text...");51 52static cl::opt<std::string> OutputDir("output-dir", cl::desc(R"(53The output directory for saving the results.)"),54                                      cl::init("."),55                                      cl::cat(FindAllSymbolsCategory));56 57static cl::opt<std::string> MergeDir("merge-dir", cl::desc(R"(58The directory for merging symbols.)"),59                                     cl::init(""),60                                     cl::cat(FindAllSymbolsCategory));61namespace clang {62namespace find_all_symbols {63 64class YamlReporter : public SymbolReporter {65public:66  void reportSymbols(StringRef FileName,67                     const SymbolInfo::SignalMap &Symbols) override {68    int FD;69    SmallString<128> ResultPath;70    llvm::sys::fs::createUniqueFile(71        OutputDir + "/" + llvm::sys::path::filename(FileName) + "-%%%%%%.yaml",72        FD, ResultPath);73    llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);74    WriteSymbolInfosToStream(OS, Symbols);75  }76};77 78bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {79  std::error_code EC;80  SymbolInfo::SignalMap Symbols;81  std::mutex SymbolMutex;82  auto AddSymbols = [&](ArrayRef<SymbolAndSignals> NewSymbols) {83    // Synchronize set accesses.84    std::unique_lock<std::mutex> LockGuard(SymbolMutex);85    for (const auto &Symbol : NewSymbols) {86      Symbols[Symbol.Symbol] += Symbol.Signals;87    }88  };89 90  // Load all symbol files in MergeDir.91  {92    llvm::DefaultThreadPool Pool;93    for (llvm::sys::fs::directory_iterator Dir(MergeDir, EC), DirEnd;94         Dir != DirEnd && !EC; Dir.increment(EC)) {95      // Parse YAML files in parallel.96      Pool.async(97          [&AddSymbols](std::string Path) {98            auto Buffer = llvm::MemoryBuffer::getFile(Path, /*IsText=*/true);99            if (!Buffer) {100              llvm::errs() << "Can't open " << Path << "\n";101              return;102            }103            std::vector<SymbolAndSignals> Symbols =104                ReadSymbolInfosFromYAML(Buffer.get()->getBuffer());105            for (auto &Symbol : Symbols) {106              // Only count one occurrence per file, to avoid spam.107              Symbol.Signals.Seen = std::min(Symbol.Signals.Seen, 1u);108              Symbol.Signals.Used = std::min(Symbol.Signals.Used, 1u);109            }110            // FIXME: Merge without creating such a heavy contention point.111            AddSymbols(Symbols);112          },113          Dir->path());114    }115  }116 117  llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_Text);118  if (EC) {119    llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message()120                 << '\n';121    return false;122  }123  WriteSymbolInfosToStream(OS, Symbols);124  return true;125}126 127} // namespace clang128} // namespace find_all_symbols129 130int main(int argc, const char **argv) {131  auto ExpectedParser =132      CommonOptionsParser::create(argc, argv, FindAllSymbolsCategory);133  if (!ExpectedParser) {134    llvm::errs() << ExpectedParser.takeError();135    return 1;136  }137 138  CommonOptionsParser &OptionsParser = ExpectedParser.get();139  ClangTool Tool(OptionsParser.getCompilations(),140                 OptionsParser.getSourcePathList());141 142  std::vector<std::string> sources = OptionsParser.getSourcePathList();143  if (sources.empty()) {144    llvm::errs() << "Must specify at least one one source file.\n";145    return 1;146  }147  if (!MergeDir.empty()) {148    clang::find_all_symbols::Merge(MergeDir, sources[0]);149    return 0;150  }151 152  clang::find_all_symbols::YamlReporter Reporter;153 154  auto Factory =155      std::make_unique<clang::find_all_symbols::FindAllSymbolsActionFactory>(156          &Reporter, clang::find_all_symbols::getSTLPostfixHeaderMap());157  return Tool.run(Factory.get());158}159