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