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