Coverage Report

Created: 2021-08-24 07:12

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