364 lines
12 KiB
C++
364 lines
12 KiB
C++
//===-- core_main.cpp - Core Index Tool testbed ---------------------------===//
|
|
//
|
|
// 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 "clang/Basic/LangOptions.h"
|
|
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
#include "clang/Frontend/CompilerInvocation.h"
|
|
#include "clang/Frontend/FrontendAction.h"
|
|
#include "clang/Index/IndexingAction.h"
|
|
#include "clang/Index/IndexDataConsumer.h"
|
|
#include "clang/Index/USRGeneration.h"
|
|
#include "clang/Index/CodegenNameGenerator.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Serialization/ASTReader.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Signals.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::index;
|
|
using namespace llvm;
|
|
|
|
extern "C" int indextest_core_main(int argc, const char **argv);
|
|
|
|
namespace {
|
|
|
|
enum class ActionType {
|
|
None,
|
|
PrintSourceSymbols,
|
|
};
|
|
|
|
namespace options {
|
|
|
|
static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
|
|
|
|
static cl::opt<ActionType>
|
|
Action(cl::desc("Action:"), cl::init(ActionType::None),
|
|
cl::values(
|
|
clEnumValN(ActionType::PrintSourceSymbols,
|
|
"print-source-symbols", "Print symbols from source")),
|
|
cl::cat(IndexTestCoreCategory));
|
|
|
|
static cl::extrahelp MoreHelp(
|
|
"\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
|
|
"invocation\n"
|
|
);
|
|
|
|
static cl::opt<bool>
|
|
DumpModuleImports("dump-imported-module-files",
|
|
cl::desc("Print symbols and input files from imported modules"));
|
|
|
|
static cl::opt<bool>
|
|
IncludeLocals("include-locals", cl::desc("Print local symbols"));
|
|
|
|
static cl::opt<std::string>
|
|
ModuleFilePath("module-file",
|
|
cl::desc("Path to module file to print symbols from"));
|
|
static cl::opt<std::string>
|
|
ModuleFormat("fmodule-format", cl::init("raw"),
|
|
cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
|
|
|
|
}
|
|
} // anonymous namespace
|
|
|
|
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS);
|
|
static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
|
|
raw_ostream &OS);
|
|
static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS);
|
|
|
|
namespace {
|
|
|
|
class PrintIndexDataConsumer : public IndexDataConsumer {
|
|
raw_ostream &OS;
|
|
std::unique_ptr<CodegenNameGenerator> CGNameGen;
|
|
std::shared_ptr<Preprocessor> PP;
|
|
|
|
public:
|
|
PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
|
|
}
|
|
|
|
void initialize(ASTContext &Ctx) override {
|
|
CGNameGen.reset(new CodegenNameGenerator(Ctx));
|
|
}
|
|
|
|
void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
|
|
this->PP = std::move(PP);
|
|
}
|
|
|
|
bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
|
|
ArrayRef<SymbolRelation> Relations,
|
|
SourceLocation Loc, ASTNodeInfo ASTNode) override {
|
|
ASTContext &Ctx = D->getASTContext();
|
|
SourceManager &SM = Ctx.getSourceManager();
|
|
|
|
Loc = SM.getFileLoc(Loc);
|
|
FileID FID = SM.getFileID(Loc);
|
|
unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
|
|
unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
|
|
OS << Line << ':' << Col << " | ";
|
|
|
|
printSymbolInfo(getSymbolInfo(D), OS);
|
|
OS << " | ";
|
|
|
|
printSymbolNameAndUSR(D, Ctx, OS);
|
|
OS << " | ";
|
|
|
|
if (CGNameGen->writeName(D, OS))
|
|
OS << "<no-cgname>";
|
|
OS << " | ";
|
|
|
|
printSymbolRoles(Roles, OS);
|
|
OS << " | ";
|
|
|
|
OS << "rel: " << Relations.size() << '\n';
|
|
|
|
for (auto &SymRel : Relations) {
|
|
OS << '\t';
|
|
printSymbolRoles(SymRel.Roles, OS);
|
|
OS << " | ";
|
|
printSymbolNameAndUSR(SymRel.RelatedSymbol, Ctx, OS);
|
|
OS << '\n';
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool handleModuleOccurence(const ImportDecl *ImportD,
|
|
const clang::Module *Mod,
|
|
SymbolRoleSet Roles, SourceLocation Loc) override {
|
|
ASTContext &Ctx = ImportD->getASTContext();
|
|
SourceManager &SM = Ctx.getSourceManager();
|
|
|
|
Loc = SM.getFileLoc(Loc);
|
|
FileID FID = SM.getFileID(Loc);
|
|
unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
|
|
unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
|
|
OS << Line << ':' << Col << " | ";
|
|
|
|
printSymbolInfo(getSymbolInfo(ImportD), OS);
|
|
OS << " | ";
|
|
|
|
printSymbolNameAndUSR(Mod, OS);
|
|
OS << " | ";
|
|
|
|
printSymbolRoles(Roles, OS);
|
|
OS << " |\n";
|
|
|
|
return true;
|
|
}
|
|
|
|
bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
|
|
SymbolRoleSet Roles, SourceLocation Loc) override {
|
|
assert(PP);
|
|
SourceManager &SM = PP->getSourceManager();
|
|
|
|
Loc = SM.getFileLoc(Loc);
|
|
FileID FID = SM.getFileID(Loc);
|
|
unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
|
|
unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
|
|
OS << Line << ':' << Col << " | ";
|
|
|
|
printSymbolInfo(getSymbolInfoForMacro(*MI), OS);
|
|
OS << " | ";
|
|
|
|
OS << Name->getName();
|
|
OS << " | ";
|
|
|
|
SmallString<256> USRBuf;
|
|
if (generateUSRForMacro(Name->getName(), MI->getDefinitionLoc(), SM,
|
|
USRBuf)) {
|
|
OS << "<no-usr>";
|
|
} else {
|
|
OS << USRBuf;
|
|
}
|
|
OS << " | ";
|
|
|
|
printSymbolRoles(Roles, OS);
|
|
OS << " |\n";
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Print Source Symbols
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static void dumpModuleFileInputs(serialization::ModuleFile &Mod,
|
|
ASTReader &Reader,
|
|
raw_ostream &OS) {
|
|
OS << "---- Module Inputs ----\n";
|
|
Reader.visitInputFiles(Mod, /*IncludeSystem=*/true, /*Complain=*/false,
|
|
[&](const serialization::InputFile &IF, bool isSystem) {
|
|
OS << (isSystem ? "system" : "user") << " | ";
|
|
OS << IF.getFile()->getName() << '\n';
|
|
});
|
|
}
|
|
|
|
static bool printSourceSymbols(const char *Executable,
|
|
ArrayRef<const char *> Args,
|
|
bool dumpModuleImports, bool indexLocals) {
|
|
SmallVector<const char *, 4> ArgsWithProgName;
|
|
ArgsWithProgName.push_back(Executable);
|
|
ArgsWithProgName.append(Args.begin(), Args.end());
|
|
IntrusiveRefCntPtr<DiagnosticsEngine>
|
|
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
|
|
auto CInvok = createInvocationFromCommandLine(ArgsWithProgName, Diags);
|
|
if (!CInvok)
|
|
return true;
|
|
|
|
raw_ostream &OS = outs();
|
|
auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(OS);
|
|
IndexingOptions IndexOpts;
|
|
IndexOpts.IndexFunctionLocals = indexLocals;
|
|
std::unique_ptr<FrontendAction> IndexAction;
|
|
IndexAction = createIndexingAction(DataConsumer, IndexOpts,
|
|
/*WrappedAction=*/nullptr);
|
|
|
|
auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
|
|
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
|
|
std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
|
|
|
|
if (!Unit)
|
|
return true;
|
|
|
|
if (dumpModuleImports) {
|
|
if (auto Reader = Unit->getASTReader()) {
|
|
Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
|
|
OS << "==== Module " << Mod.ModuleName << " ====\n";
|
|
indexModuleFile(Mod, *Reader, *DataConsumer, IndexOpts);
|
|
dumpModuleFileInputs(Mod, *Reader, OS);
|
|
return true; // skip module dependencies.
|
|
});
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool printSourceSymbolsFromModule(StringRef modulePath,
|
|
StringRef format) {
|
|
FileSystemOptions FileSystemOpts;
|
|
auto pchContOps = std::make_shared<PCHContainerOperations>();
|
|
// Register the support for object-file-wrapped Clang modules.
|
|
pchContOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
|
|
auto pchRdr = pchContOps->getReaderOrNull(format);
|
|
if (!pchRdr) {
|
|
errs() << "unknown module format: " << format << '\n';
|
|
return true;
|
|
}
|
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
|
|
CompilerInstance::createDiagnostics(new DiagnosticOptions());
|
|
std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
|
|
modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
|
|
FileSystemOpts, /*UseDebugInfo=*/false,
|
|
/*OnlyLocalDecls=*/true, None,
|
|
CaptureDiagsKind::None,
|
|
/*AllowPCHWithCompilerErrors=*/true,
|
|
/*UserFilesAreVolatile=*/false);
|
|
if (!AU) {
|
|
errs() << "failed to create TU for: " << modulePath << '\n';
|
|
return true;
|
|
}
|
|
|
|
PrintIndexDataConsumer DataConsumer(outs());
|
|
IndexingOptions IndexOpts;
|
|
indexASTUnit(*AU, DataConsumer, IndexOpts);
|
|
|
|
return false;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Helper Utils
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
|
|
OS << getSymbolKindString(SymInfo.Kind);
|
|
if (SymInfo.SubKind != SymbolSubKind::None)
|
|
OS << '/' << getSymbolSubKindString(SymInfo.SubKind);
|
|
if (SymInfo.Properties) {
|
|
OS << '(';
|
|
printSymbolProperties(SymInfo.Properties, OS);
|
|
OS << ')';
|
|
}
|
|
OS << '/' << getSymbolLanguageString(SymInfo.Lang);
|
|
}
|
|
|
|
static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
|
|
raw_ostream &OS) {
|
|
if (printSymbolName(D, Ctx.getLangOpts(), OS)) {
|
|
OS << "<no-name>";
|
|
}
|
|
OS << " | ";
|
|
|
|
SmallString<256> USRBuf;
|
|
if (generateUSRForDecl(D, USRBuf)) {
|
|
OS << "<no-usr>";
|
|
} else {
|
|
OS << USRBuf;
|
|
}
|
|
}
|
|
|
|
static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS) {
|
|
assert(Mod);
|
|
OS << Mod->getFullModuleName() << " | ";
|
|
generateFullUSRForModule(Mod, OS);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Command line processing.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
int indextest_core_main(int argc, const char **argv) {
|
|
sys::PrintStackTraceOnErrorSignal(argv[0]);
|
|
PrettyStackTraceProgram X(argc, argv);
|
|
void *MainAddr = (void*) (intptr_t) indextest_core_main;
|
|
std::string Executable = llvm::sys::fs::getMainExecutable(argv[0], MainAddr);
|
|
|
|
assert(argv[1] == StringRef("core"));
|
|
++argv;
|
|
--argc;
|
|
|
|
std::vector<const char *> CompArgs;
|
|
const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
|
|
if (DoubleDash != argv + argc) {
|
|
CompArgs = std::vector<const char *>(DoubleDash + 1, argv + argc);
|
|
argc = DoubleDash - argv;
|
|
}
|
|
|
|
cl::HideUnrelatedOptions(options::IndexTestCoreCategory);
|
|
cl::ParseCommandLineOptions(argc, argv, "index-test-core");
|
|
|
|
if (options::Action == ActionType::None) {
|
|
errs() << "error: action required; pass '-help' for options\n";
|
|
return 1;
|
|
}
|
|
|
|
if (options::Action == ActionType::PrintSourceSymbols) {
|
|
if (!options::ModuleFilePath.empty()) {
|
|
return printSourceSymbolsFromModule(options::ModuleFilePath,
|
|
options::ModuleFormat);
|
|
}
|
|
if (CompArgs.empty()) {
|
|
errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
|
|
return 1;
|
|
}
|
|
return printSourceSymbols(Executable.c_str(), CompArgs,
|
|
options::DumpModuleImports,
|
|
options::IncludeLocals);
|
|
}
|
|
|
|
return 0;
|
|
}
|