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