Clang Project

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