Coverage Report

Created: 2020-02-25 14:32

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