core_main.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //===-- core_main.cpp - Core Index Tool testbed ---------------------------===//
  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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/Basic/LangOptions.h"
  9. #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
  10. #include "clang/Frontend/ASTUnit.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Frontend/CompilerInvocation.h"
  13. #include "clang/Frontend/FrontendAction.h"
  14. #include "clang/Index/IndexingAction.h"
  15. #include "clang/Index/IndexDataConsumer.h"
  16. #include "clang/Index/USRGeneration.h"
  17. #include "clang/Index/CodegenNameGenerator.h"
  18. #include "clang/Lex/Preprocessor.h"
  19. #include "clang/Serialization/ASTReader.h"
  20. #include "llvm/Support/CommandLine.h"
  21. #include "llvm/Support/FileSystem.h"
  22. #include "llvm/Support/Signals.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. #include "llvm/Support/PrettyStackTrace.h"
  25. using namespace clang;
  26. using namespace clang::index;
  27. using namespace llvm;
  28. extern "C" int indextest_core_main(int argc, const char **argv);
  29. namespace {
  30. enum class ActionType {
  31. None,
  32. PrintSourceSymbols,
  33. };
  34. namespace options {
  35. static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
  36. static cl::opt<ActionType>
  37. Action(cl::desc("Action:"), cl::init(ActionType::None),
  38. cl::values(
  39. clEnumValN(ActionType::PrintSourceSymbols,
  40. "print-source-symbols", "Print symbols from source")),
  41. cl::cat(IndexTestCoreCategory));
  42. static cl::extrahelp MoreHelp(
  43. "\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
  44. "invocation\n"
  45. );
  46. static cl::opt<bool>
  47. DumpModuleImports("dump-imported-module-files",
  48. cl::desc("Print symbols and input files from imported modules"));
  49. static cl::opt<bool>
  50. IncludeLocals("include-locals", cl::desc("Print local symbols"));
  51. static cl::opt<std::string>
  52. ModuleFilePath("module-file",
  53. cl::desc("Path to module file to print symbols from"));
  54. static cl::opt<std::string>
  55. ModuleFormat("fmodule-format", cl::init("raw"),
  56. cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
  57. }
  58. } // anonymous namespace
  59. static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS);
  60. static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
  61. raw_ostream &OS);
  62. static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS);
  63. namespace {
  64. class PrintIndexDataConsumer : public IndexDataConsumer {
  65. raw_ostream &OS;
  66. std::unique_ptr<CodegenNameGenerator> CGNameGen;
  67. std::shared_ptr<Preprocessor> PP;
  68. public:
  69. PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
  70. }
  71. void initialize(ASTContext &Ctx) override {
  72. CGNameGen.reset(new CodegenNameGenerator(Ctx));
  73. }
  74. void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
  75. this->PP = std::move(PP);
  76. }
  77. bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
  78. ArrayRef<SymbolRelation> Relations,
  79. SourceLocation Loc, ASTNodeInfo ASTNode) override {
  80. ASTContext &Ctx = D->getASTContext();
  81. SourceManager &SM = Ctx.getSourceManager();
  82. Loc = SM.getFileLoc(Loc);
  83. FileID FID = SM.getFileID(Loc);
  84. unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
  85. unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
  86. OS << Line << ':' << Col << " | ";
  87. printSymbolInfo(getSymbolInfo(D), OS);
  88. OS << " | ";
  89. printSymbolNameAndUSR(D, Ctx, OS);
  90. OS << " | ";
  91. if (CGNameGen->writeName(D, OS))
  92. OS << "<no-cgname>";
  93. OS << " | ";
  94. printSymbolRoles(Roles, OS);
  95. OS << " | ";
  96. OS << "rel: " << Relations.size() << '\n';
  97. for (auto &SymRel : Relations) {
  98. OS << '\t';
  99. printSymbolRoles(SymRel.Roles, OS);
  100. OS << " | ";
  101. printSymbolNameAndUSR(SymRel.RelatedSymbol, Ctx, OS);
  102. OS << '\n';
  103. }
  104. return true;
  105. }
  106. bool handleModuleOccurence(const ImportDecl *ImportD,
  107. const clang::Module *Mod,
  108. SymbolRoleSet Roles, SourceLocation Loc) override {
  109. ASTContext &Ctx = ImportD->getASTContext();
  110. SourceManager &SM = Ctx.getSourceManager();
  111. Loc = SM.getFileLoc(Loc);
  112. FileID FID = SM.getFileID(Loc);
  113. unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
  114. unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
  115. OS << Line << ':' << Col << " | ";
  116. printSymbolInfo(getSymbolInfo(ImportD), OS);
  117. OS << " | ";
  118. printSymbolNameAndUSR(Mod, OS);
  119. OS << " | ";
  120. printSymbolRoles(Roles, OS);
  121. OS << " |\n";
  122. return true;
  123. }
  124. bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
  125. SymbolRoleSet Roles, SourceLocation Loc) override {
  126. assert(PP);
  127. SourceManager &SM = PP->getSourceManager();
  128. Loc = SM.getFileLoc(Loc);
  129. FileID FID = SM.getFileID(Loc);
  130. unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
  131. unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
  132. OS << Line << ':' << Col << " | ";
  133. printSymbolInfo(getSymbolInfoForMacro(*MI), OS);
  134. OS << " | ";
  135. OS << Name->getName();
  136. OS << " | ";
  137. SmallString<256> USRBuf;
  138. if (generateUSRForMacro(Name->getName(), MI->getDefinitionLoc(), SM,
  139. USRBuf)) {
  140. OS << "<no-usr>";
  141. } else {
  142. OS << USRBuf;
  143. }
  144. OS << " | ";
  145. printSymbolRoles(Roles, OS);
  146. OS << " |\n";
  147. return true;
  148. }
  149. };
  150. } // anonymous namespace
  151. //===----------------------------------------------------------------------===//
  152. // Print Source Symbols
  153. //===----------------------------------------------------------------------===//
  154. static void dumpModuleFileInputs(serialization::ModuleFile &Mod,
  155. ASTReader &Reader,
  156. raw_ostream &OS) {
  157. OS << "---- Module Inputs ----\n";
  158. Reader.visitInputFiles(Mod, /*IncludeSystem=*/true, /*Complain=*/false,
  159. [&](const serialization::InputFile &IF, bool isSystem) {
  160. OS << (isSystem ? "system" : "user") << " | ";
  161. OS << IF.getFile()->getName() << '\n';
  162. });
  163. }
  164. static bool printSourceSymbols(const char *Executable,
  165. ArrayRef<const char *> Args,
  166. bool dumpModuleImports, bool indexLocals) {
  167. SmallVector<const char *, 4> ArgsWithProgName;
  168. ArgsWithProgName.push_back(Executable);
  169. ArgsWithProgName.append(Args.begin(), Args.end());
  170. IntrusiveRefCntPtr<DiagnosticsEngine>
  171. Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
  172. auto CInvok = createInvocationFromCommandLine(ArgsWithProgName, Diags);
  173. if (!CInvok)
  174. return true;
  175. raw_ostream &OS = outs();
  176. auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(OS);
  177. IndexingOptions IndexOpts;
  178. IndexOpts.IndexFunctionLocals = indexLocals;
  179. std::unique_ptr<FrontendAction> IndexAction;
  180. IndexAction = createIndexingAction(DataConsumer, IndexOpts,
  181. /*WrappedAction=*/nullptr);
  182. auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
  183. std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
  184. std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
  185. if (!Unit)
  186. return true;
  187. if (dumpModuleImports) {
  188. if (auto Reader = Unit->getASTReader()) {
  189. Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
  190. OS << "==== Module " << Mod.ModuleName << " ====\n";
  191. indexModuleFile(Mod, *Reader, *DataConsumer, IndexOpts);
  192. dumpModuleFileInputs(Mod, *Reader, OS);
  193. return true; // skip module dependencies.
  194. });
  195. }
  196. }
  197. return false;
  198. }
  199. static bool printSourceSymbolsFromModule(StringRef modulePath,
  200. StringRef format) {
  201. FileSystemOptions FileSystemOpts;
  202. auto pchContOps = std::make_shared<PCHContainerOperations>();
  203. // Register the support for object-file-wrapped Clang modules.
  204. pchContOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
  205. auto pchRdr = pchContOps->getReaderOrNull(format);
  206. if (!pchRdr) {
  207. errs() << "unknown module format: " << format << '\n';
  208. return true;
  209. }
  210. IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
  211. CompilerInstance::createDiagnostics(new DiagnosticOptions());
  212. std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
  213. modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
  214. FileSystemOpts, /*UseDebugInfo=*/false,
  215. /*OnlyLocalDecls=*/true, None,
  216. CaptureDiagsKind::None,
  217. /*AllowPCHWithCompilerErrors=*/true,
  218. /*UserFilesAreVolatile=*/false);
  219. if (!AU) {
  220. errs() << "failed to create TU for: " << modulePath << '\n';
  221. return true;
  222. }
  223. PrintIndexDataConsumer DataConsumer(outs());
  224. IndexingOptions IndexOpts;
  225. indexASTUnit(*AU, DataConsumer, IndexOpts);
  226. return false;
  227. }
  228. //===----------------------------------------------------------------------===//
  229. // Helper Utils
  230. //===----------------------------------------------------------------------===//
  231. static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
  232. OS << getSymbolKindString(SymInfo.Kind);
  233. if (SymInfo.SubKind != SymbolSubKind::None)
  234. OS << '/' << getSymbolSubKindString(SymInfo.SubKind);
  235. if (SymInfo.Properties) {
  236. OS << '(';
  237. printSymbolProperties(SymInfo.Properties, OS);
  238. OS << ')';
  239. }
  240. OS << '/' << getSymbolLanguageString(SymInfo.Lang);
  241. }
  242. static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
  243. raw_ostream &OS) {
  244. if (printSymbolName(D, Ctx.getLangOpts(), OS)) {
  245. OS << "<no-name>";
  246. }
  247. OS << " | ";
  248. SmallString<256> USRBuf;
  249. if (generateUSRForDecl(D, USRBuf)) {
  250. OS << "<no-usr>";
  251. } else {
  252. OS << USRBuf;
  253. }
  254. }
  255. static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS) {
  256. assert(Mod);
  257. OS << Mod->getFullModuleName() << " | ";
  258. generateFullUSRForModule(Mod, OS);
  259. }
  260. //===----------------------------------------------------------------------===//
  261. // Command line processing.
  262. //===----------------------------------------------------------------------===//
  263. int indextest_core_main(int argc, const char **argv) {
  264. sys::PrintStackTraceOnErrorSignal(argv[0]);
  265. PrettyStackTraceProgram X(argc, argv);
  266. void *MainAddr = (void*) (intptr_t) indextest_core_main;
  267. std::string Executable = llvm::sys::fs::getMainExecutable(argv[0], MainAddr);
  268. assert(argv[1] == StringRef("core"));
  269. ++argv;
  270. --argc;
  271. std::vector<const char *> CompArgs;
  272. const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
  273. if (DoubleDash != argv + argc) {
  274. CompArgs = std::vector<const char *>(DoubleDash + 1, argv + argc);
  275. argc = DoubleDash - argv;
  276. }
  277. cl::HideUnrelatedOptions(options::IndexTestCoreCategory);
  278. cl::ParseCommandLineOptions(argc, argv, "index-test-core");
  279. if (options::Action == ActionType::None) {
  280. errs() << "error: action required; pass '-help' for options\n";
  281. return 1;
  282. }
  283. if (options::Action == ActionType::PrintSourceSymbols) {
  284. if (!options::ModuleFilePath.empty()) {
  285. return printSourceSymbolsFromModule(options::ModuleFilePath,
  286. options::ModuleFormat);
  287. }
  288. if (CompArgs.empty()) {
  289. errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
  290. return 1;
  291. }
  292. return printSourceSymbols(Executable.c_str(), CompArgs,
  293. options::DumpModuleImports,
  294. options::IncludeLocals);
  295. }
  296. return 0;
  297. }