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/Frontend/ASTUnit.h"
11#include "clang/Frontend/CompilerInstance.h"
12#include "clang/Frontend/CompilerInvocation.h"
13#include "clang/Frontend/FrontendAction.h"
14#include "clang/Index/IndexingAction.h"
15#include "clang/Index/IndexDataConsumer.h"
16#include "clang/Index/USRGeneration.h"
17#include "clang/Index/CodegenNameGenerator.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/Signals.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/Support/PrettyStackTrace.h"
22
23using namespace clang;
24using namespace clang::index;
25using namespace llvm;
26
27extern "C" int indextest_core_main(int argc, const char **argv);
28
29namespace {
30
31enum class ActionType {
32  None,
33  PrintSourceSymbols,
34};
35
36namespace options {
37
38static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
39
40static cl::opt<ActionType>
41Action(cl::desc("Action:"), cl::init(ActionType::None),
42       cl::values(
43          clEnumValN(ActionType::PrintSourceSymbols,
44                     "print-source-symbols", "Print symbols from source"),
45          clEnumValEnd),
46       cl::cat(IndexTestCoreCategory));
47
48static cl::extrahelp MoreHelp(
49  "\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
50  "invocation\n"
51);
52
53}
54} // anonymous namespace
55
56static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS);
57static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
58                                  raw_ostream &OS);
59
60namespace {
61
62class PrintIndexDataConsumer : public IndexDataConsumer {
63  raw_ostream &OS;
64  std::unique_ptr<CodegenNameGenerator> CGNameGen;
65
66public:
67  PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
68  }
69
70  void initialize(ASTContext &Ctx) override {
71    CGNameGen.reset(new CodegenNameGenerator(Ctx));
72  }
73
74  bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
75                           ArrayRef<SymbolRelation> Relations,
76                           FileID FID, unsigned Offset,
77                           ASTNodeInfo ASTNode) override {
78    ASTContext &Ctx = D->getASTContext();
79    SourceManager &SM = Ctx.getSourceManager();
80
81    unsigned Line = SM.getLineNumber(FID, Offset);
82    unsigned Col = SM.getColumnNumber(FID, Offset);
83    OS << Line << ':' << Col << " | ";
84
85    printSymbolInfo(getSymbolInfo(D), OS);
86    OS << " | ";
87
88    printSymbolNameAndUSR(D, Ctx, OS);
89    OS << " | ";
90
91    if (CGNameGen->writeName(D, OS))
92      OS << "<no-cgname>";
93    OS << " | ";
94
95    printSymbolRoles(Roles, OS);
96    OS << " | ";
97
98    OS << "rel: " << Relations.size() << '\n';
99
100    for (auto &SymRel : Relations) {
101      OS << '\t';
102      printSymbolRoles(SymRel.Roles, OS);
103      OS << " | ";
104      printSymbolNameAndUSR(SymRel.RelatedSymbol, Ctx, OS);
105      OS << '\n';
106    }
107
108    return true;
109  }
110
111  bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles,
112                             FileID FID, unsigned Offset) override {
113    ASTContext &Ctx = ImportD->getASTContext();
114    SourceManager &SM = Ctx.getSourceManager();
115
116    unsigned Line = SM.getLineNumber(FID, Offset);
117    unsigned Col = SM.getColumnNumber(FID, Offset);
118    OS << Line << ':' << Col << " | ";
119
120    printSymbolInfo(getSymbolInfo(ImportD), OS);
121    OS << " | ";
122
123    OS << ImportD->getImportedModule()->getFullModuleName() << " | ";
124
125    printSymbolRoles(Roles, OS);
126    OS << " |\n";
127
128    return true;
129  }
130};
131
132} // anonymous namespace
133
134//===----------------------------------------------------------------------===//
135// Print Source Symbols
136//===----------------------------------------------------------------------===//
137
138static bool printSourceSymbols(ArrayRef<const char *> Args) {
139  SmallVector<const char *, 4> ArgsWithProgName;
140  ArgsWithProgName.push_back("clang");
141  ArgsWithProgName.append(Args.begin(), Args.end());
142  IntrusiveRefCntPtr<DiagnosticsEngine>
143    Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
144  IntrusiveRefCntPtr<CompilerInvocation>
145    CInvok(createInvocationFromCommandLine(ArgsWithProgName, Diags));
146  if (!CInvok)
147    return true;
148
149  auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
150  IndexingOptions IndexOpts;
151  std::unique_ptr<FrontendAction> IndexAction;
152  IndexAction = createIndexingAction(DataConsumer, IndexOpts,
153                                     /*WrappedAction=*/nullptr);
154
155  auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
156  std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
157      CInvok.get(), PCHContainerOps, Diags, IndexAction.get()));
158
159  if (!Unit)
160    return true;
161
162  return false;
163}
164
165//===----------------------------------------------------------------------===//
166// Helper Utils
167//===----------------------------------------------------------------------===//
168
169static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
170  OS << getSymbolKindString(SymInfo.Kind);
171  if (SymInfo.SubKinds) {
172    OS << '(';
173    printSymbolSubKinds(SymInfo.SubKinds, OS);
174    OS << ')';
175  }
176  OS << '/' << getSymbolLanguageString(SymInfo.Lang);
177}
178
179static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
180                                  raw_ostream &OS) {
181  if (printSymbolName(D, Ctx.getLangOpts(), OS)) {
182    OS << "<no-name>";
183  }
184  OS << " | ";
185
186  SmallString<256> USRBuf;
187  if (generateUSRForDecl(D, USRBuf)) {
188    OS << "<no-usr>";
189  } else {
190    OS << USRBuf;
191  }
192}
193
194//===----------------------------------------------------------------------===//
195// Command line processing.
196//===----------------------------------------------------------------------===//
197
198int indextest_core_main(int argc, const char **argv) {
199  sys::PrintStackTraceOnErrorSignal(argv[0]);
200  PrettyStackTraceProgram X(argc, argv);
201
202  assert(argv[1] == StringRef("core"));
203  ++argv;
204  --argc;
205
206  std::vector<const char *> CompArgs;
207  const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
208  if (DoubleDash != argv + argc) {
209    CompArgs = std::vector<const char *>(DoubleDash + 1, argv + argc);
210    argc = DoubleDash - argv;
211  }
212
213  cl::HideUnrelatedOptions(options::IndexTestCoreCategory);
214  cl::ParseCommandLineOptions(argc, argv, "index-test-core");
215
216  if (options::Action == ActionType::None) {
217    errs() << "error: action required; pass '-help' for options\n";
218    return 1;
219  }
220
221  if (options::Action == ActionType::PrintSourceSymbols) {
222    if (CompArgs.empty()) {
223      errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
224      return 1;
225    }
226    return printSourceSymbols(CompArgs);
227  }
228
229  return 0;
230}
231