Coverage Report

Created: 2023-11-11 10:31

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