core_main.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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/AST/Mangle.h"
  9. #include "clang/Basic/LangOptions.h"
  10. #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
  11. #include "clang/Frontend/ASTUnit.h"
  12. #include "clang/Frontend/CompilerInstance.h"
  13. #include "clang/Frontend/CompilerInvocation.h"
  14. #include "clang/Frontend/FrontendAction.h"
  15. #include "clang/Index/IndexingAction.h"
  16. #include "clang/Index/IndexDataConsumer.h"
  17. #include "clang/Index/USRGeneration.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<ASTNameGenerator> ASTNameGen;
  67. std::shared_ptr<Preprocessor> PP;
  68. public:
  69. PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
  70. }
  71. void initialize(ASTContext &Ctx) override {
  72. ASTNameGen.reset(new ASTNameGenerator(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 (ASTNameGen->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. createIndexingAction(DataConsumer, IndexOpts);
  181. auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
  182. std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
  183. std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
  184. if (!Unit)
  185. return true;
  186. if (dumpModuleImports) {
  187. if (auto Reader = Unit->getASTReader()) {
  188. Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
  189. OS << "==== Module " << Mod.ModuleName << " ====\n";
  190. indexModuleFile(Mod, *Reader, *DataConsumer, IndexOpts);
  191. dumpModuleFileInputs(Mod, *Reader, OS);
  192. return true; // skip module dependencies.
  193. });
  194. }
  195. }
  196. return false;
  197. }
  198. static bool printSourceSymbolsFromModule(StringRef modulePath,
  199. StringRef format) {
  200. FileSystemOptions FileSystemOpts;
  201. auto pchContOps = std::make_shared<PCHContainerOperations>();
  202. // Register the support for object-file-wrapped Clang modules.
  203. pchContOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
  204. auto pchRdr = pchContOps->getReaderOrNull(format);
  205. if (!pchRdr) {
  206. errs() << "unknown module format: " << format << '\n';
  207. return true;
  208. }
  209. IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
  210. CompilerInstance::createDiagnostics(new DiagnosticOptions());
  211. std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
  212. modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
  213. FileSystemOpts, /*UseDebugInfo=*/false,
  214. /*OnlyLocalDecls=*/true, None,
  215. CaptureDiagsKind::None,
  216. /*AllowPCHWithCompilerErrors=*/true,
  217. /*UserFilesAreVolatile=*/false);
  218. if (!AU) {
  219. errs() << "failed to create TU for: " << modulePath << '\n';
  220. return true;
  221. }
  222. PrintIndexDataConsumer DataConsumer(outs());
  223. IndexingOptions IndexOpts;
  224. indexASTUnit(*AU, DataConsumer, IndexOpts);
  225. return false;
  226. }
  227. //===----------------------------------------------------------------------===//
  228. // Helper Utils
  229. //===----------------------------------------------------------------------===//
  230. static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
  231. OS << getSymbolKindString(SymInfo.Kind);
  232. if (SymInfo.SubKind != SymbolSubKind::None)
  233. OS << '/' << getSymbolSubKindString(SymInfo.SubKind);
  234. if (SymInfo.Properties) {
  235. OS << '(';
  236. printSymbolProperties(SymInfo.Properties, OS);
  237. OS << ')';
  238. }
  239. OS << '/' << getSymbolLanguageString(SymInfo.Lang);
  240. }
  241. static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
  242. raw_ostream &OS) {
  243. if (printSymbolName(D, Ctx.getLangOpts(), OS)) {
  244. OS << "<no-name>";
  245. }
  246. OS << " | ";
  247. SmallString<256> USRBuf;
  248. if (generateUSRForDecl(D, USRBuf)) {
  249. OS << "<no-usr>";
  250. } else {
  251. OS << USRBuf;
  252. }
  253. }
  254. static void printSymbolNameAndUSR(const clang::Module *Mod, raw_ostream &OS) {
  255. assert(Mod);
  256. OS << Mod->getFullModuleName() << " | ";
  257. generateFullUSRForModule(Mod, OS);
  258. }
  259. //===----------------------------------------------------------------------===//
  260. // Command line processing.
  261. //===----------------------------------------------------------------------===//
  262. int indextest_core_main(int argc, const char **argv) {
  263. sys::PrintStackTraceOnErrorSignal(argv[0]);
  264. PrettyStackTraceProgram X(argc, argv);
  265. void *MainAddr = (void*) (intptr_t) indextest_core_main;
  266. std::string Executable = llvm::sys::fs::getMainExecutable(argv[0], MainAddr);
  267. assert(argv[1] == StringRef("core"));
  268. ++argv;
  269. --argc;
  270. std::vector<const char *> CompArgs;
  271. const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
  272. if (DoubleDash != argv + argc) {
  273. CompArgs = std::vector<const char *>(DoubleDash + 1, argv + argc);
  274. argc = DoubleDash - argv;
  275. }
  276. cl::HideUnrelatedOptions(options::IndexTestCoreCategory);
  277. cl::ParseCommandLineOptions(argc, argv, "index-test-core");
  278. if (options::Action == ActionType::None) {
  279. errs() << "error: action required; pass '-help' for options\n";
  280. return 1;
  281. }
  282. if (options::Action == ActionType::PrintSourceSymbols) {
  283. if (!options::ModuleFilePath.empty()) {
  284. return printSourceSymbolsFromModule(options::ModuleFilePath,
  285. options::ModuleFormat);
  286. }
  287. if (CompArgs.empty()) {
  288. errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
  289. return 1;
  290. }
  291. return printSourceSymbols(Executable.c_str(), CompArgs,
  292. options::DumpModuleImports,
  293. options::IncludeLocals);
  294. }
  295. return 0;
  296. }