//===-- core_main.cpp - Core Index Tool testbed ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #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/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 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 \"-- \" at the end to setup the compiler " "invocation\n" ); static cl::opt DumpModuleImports("dump-imported-module-files", cl::desc("Print symbols and input files from imported modules")); static cl::opt IncludeLocals("include-locals", cl::desc("Print local symbols")); static cl::opt ModuleFilePath("module-file", cl::desc("Path to module file to print symbols from")); static cl::opt 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); namespace { class PrintIndexDataConsumer : public IndexDataConsumer { raw_ostream &OS; std::unique_ptr CGNameGen; std::shared_ptr PP; public: PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) { } void initialize(ASTContext &Ctx) override { CGNameGen.reset(new CodegenNameGenerator(Ctx)); } void setPreprocessor(std::shared_ptr PP) override { this->PP = std::move(PP); } bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef 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 << ""; 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, 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 << " | "; OS << ImportD->getImportedModule()->getFullModuleName() << " | "; 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 << ""; } 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(ArrayRef Args, bool dumpModuleImports, bool indexLocals) { SmallVector ArgsWithProgName; ArgsWithProgName.push_back("clang"); ArgsWithProgName.append(Args.begin(), Args.end()); IntrusiveRefCntPtr Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); auto CInvok = createInvocationFromCommandLine(ArgsWithProgName, Diags); if (!CInvok) return true; raw_ostream &OS = outs(); auto DataConsumer = std::make_shared(OS); IndexingOptions IndexOpts; IndexOpts.IndexFunctionLocals = indexLocals; std::unique_ptr IndexAction; IndexAction = createIndexingAction(DataConsumer, IndexOpts, /*WrappedAction=*/nullptr); auto PCHContainerOps = std::make_shared(); std::unique_ptr 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(); // Register the support for object-file-wrapped Clang modules. pchContOps->registerReader(llvm::make_unique()); auto pchRdr = pchContOps->getReaderOrNull(format); if (!pchRdr) { errs() << "unknown module format: " << format << '\n'; return true; } IntrusiveRefCntPtr Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); std::unique_ptr AU = ASTUnit::LoadFromASTFile( modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags, FileSystemOpts, /*UseDebugInfo=*/false, /*OnlyLocalDecls=*/true, None, /*CaptureDiagnostics=*/false, /*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 << ""; } OS << " | "; SmallString<256> USRBuf; if (generateUSRForDecl(D, USRBuf)) { OS << ""; } else { OS << USRBuf; } } //===----------------------------------------------------------------------===// // Command line processing. //===----------------------------------------------------------------------===// int indextest_core_main(int argc, const char **argv) { sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); assert(argv[1] == StringRef("core")); ++argv; --argc; std::vector CompArgs; const char **DoubleDash = std::find(argv, argv + argc, StringRef("--")); if (DoubleDash != argv + argc) { CompArgs = std::vector(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 '-- '\n"; return 1; } return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals); } return 0; }