blob: 8b12c0ba8cd080bb89fe026a967f68cc999d1633 [file] [log] [blame]
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +00001//===--- index-test.cpp - Indexing test bed -------------------------------===//
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// This utility may be invoked in the following manner:
11// index-test --help - Output help info.
12// index-test [options] - Read from stdin.
13// index-test [options] file - Read from "file".
14// index-test [options] file1 file2 - Read these files.
15//
16// Files must be AST files.
17//
18//===----------------------------------------------------------------------===//
19//
Zhongxing Xu96bac6b2009-07-07 07:14:55 +000020// -point-at [file:line:column]
Argyrios Kyrtzidis6e4a86d2009-06-25 21:54:50 +000021// Point at a declaration/statement/expression. If no other operation is
22// specified, prints some info about it.
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000023//
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000024// -print-refs
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +000025// Print ASTLocations that reference the -point-at node
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000026//
27// -print-defs
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +000028// Print ASTLocations that define the -point-at node
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000029//
30// -print-decls
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +000031// Print ASTLocations that declare the -point-at node
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000032//
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000033//===----------------------------------------------------------------------===//
34
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000035#include "clang/Index/Program.h"
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +000036#include "clang/Index/Indexer.h"
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000037#include "clang/Index/Entity.h"
38#include "clang/Index/TranslationUnit.h"
Argyrios Kyrtzidisccbcb702009-07-06 21:34:47 +000039#include "clang/Index/ASTLocation.h"
40#include "clang/Index/DeclReferenceMap.h"
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000041#include "clang/Index/SelectorMap.h"
Argyrios Kyrtzidis94431b52009-07-29 23:39:03 +000042#include "clang/Index/Handlers.h"
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +000043#include "clang/Index/Analyzer.h"
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000044#include "clang/Index/Utils.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000045#include "clang/Frontend/ASTUnit.h"
Daniel Dunbar521bf9c2009-12-01 09:51:01 +000046#include "clang/Frontend/CompilerInstance.h"
47#include "clang/Frontend/CompilerInvocation.h"
48#include "clang/Frontend/DiagnosticOptions.h"
49#include "clang/Frontend/TextDiagnosticPrinter.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000050#include "clang/Frontend/CommandLineSourceLoc.h"
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000051#include "clang/AST/DeclObjC.h"
52#include "clang/AST/ExprObjC.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000053#include "clang/Basic/FileManager.h"
54#include "clang/Basic/SourceManager.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000055#include "llvm/Support/CommandLine.h"
56#include "llvm/Support/ManagedStatic.h"
57#include "llvm/Support/PrettyStackTrace.h"
58#include "llvm/Support/raw_ostream.h"
59#include "llvm/System/Signals.h"
60using namespace clang;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000061using namespace idx;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000062
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000063class TUnit : public TranslationUnit {
64public:
65 TUnit(ASTUnit *ast, const std::string &filename)
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000066 : AST(ast), Filename(filename),
67 DeclRefMap(ast->getASTContext()),
68 SelMap(ast->getASTContext()) { }
Mike Stump1eb44332009-09-09 15:08:12 +000069
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000070 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000071 virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000072 virtual SelectorMap &getSelectorMap() { return SelMap; }
Mike Stump1eb44332009-09-09 15:08:12 +000073
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000074 llvm::OwningPtr<ASTUnit> AST;
75 std::string Filename;
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000076 DeclReferenceMap DeclRefMap;
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000077 SelectorMap SelMap;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000078};
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000079
80static llvm::cl::list<ParsedSourceLocation>
81PointAtLocation("point-at", llvm::cl::Optional,
82 llvm::cl::value_desc("source-location"),
83 llvm::cl::desc("Point at the given source location of the first AST file"));
84
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000085enum ProgActions {
86 PrintPoint, // Just print the point-at node
87 PrintRefs, // Print references of the point-at node
88 PrintDefs, // Print definitions of the point-at node
89 PrintDecls // Print declarations of the point-at node
90};
91
Mike Stump1eb44332009-09-09 15:08:12 +000092static llvm::cl::opt<ProgActions>
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000093ProgAction(
94 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
95 llvm::cl::ZeroOrMore,
96 llvm::cl::init(PrintPoint),
97 llvm::cl::values(
98 clEnumValN(PrintRefs, "print-refs",
99 "Print references"),
100 clEnumValN(PrintDefs, "print-defs",
101 "Print definitions"),
102 clEnumValN(PrintDecls, "print-decls",
103 "Print declarations"),
104 clEnumValEnd));
105
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000106static llvm::cl::opt<bool>
107DisableFree("disable-free",
108 llvm::cl::desc("Disable freeing of memory on exit"),
109 llvm::cl::init(false));
110
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000111static bool HadErrors = false;
112
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000113static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
114 llvm::raw_ostream &OS = llvm::outs();
115 typedef Storing<TULocationHandler> ResultsTy;
116 ResultsTy Results;
117
118 Analyzer Analyz(Idxer.getProgram(), Idxer);
119
120 switch (ProgAction) {
121 default: assert(0);
122 case PrintRefs:
123 llvm::errs() << "Error: Cannot -print-refs on a ObjC message expression\n";
124 HadErrors = true;
125 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000126
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000127 case PrintDecls: {
128 Analyz.FindObjCMethods(Msg, Results);
129 for (ResultsTy::iterator
130 I = Results.begin(), E = Results.end(); I != E; ++I)
131 I->print(OS);
132 break;
133 }
134
135 case PrintDefs: {
136 Analyz.FindObjCMethods(Msg, Results);
137 for (ResultsTy::iterator
138 I = Results.begin(), E = Results.end(); I != E; ++I) {
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000139 const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->AsDecl());
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000140 if (D->isThisDeclarationADefinition())
141 I->print(OS);
142 }
143 break;
144 }
145
146 }
147}
148
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000149static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000150 assert(ASTLoc.isValid());
Mike Stump1eb44332009-09-09 15:08:12 +0000151
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000152 if (ObjCMessageExpr *Msg =
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000153 dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.dyn_AsStmt()))
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000154 return ProcessObjCMessage(Msg, Idxer);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000155
Argyrios Kyrtzidisdc50c642009-07-18 21:17:58 +0000156 Decl *D = ASTLoc.getReferencedDecl();
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000157 if (D == 0) {
Argyrios Kyrtzidisec930d32009-07-21 00:05:10 +0000158 llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000159 HadErrors = true;
160 return;
161 }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000162
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000163 llvm::raw_ostream &OS = llvm::outs();
164 typedef Storing<TULocationHandler> ResultsTy;
165 ResultsTy Results;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000166
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000167 Analyzer Analyz(Idxer.getProgram(), Idxer);
Argyrios Kyrtzidis94431b52009-07-29 23:39:03 +0000168
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000169 switch (ProgAction) {
170 default: assert(0);
171 case PrintRefs: {
172 Analyz.FindReferences(D, Results);
173 for (ResultsTy::iterator
174 I = Results.begin(), E = Results.end(); I != E; ++I)
175 I->print(OS);
176 break;
177 }
178
179 case PrintDecls: {
180 Analyz.FindDeclarations(D, Results);
181 for (ResultsTy::iterator
182 I = Results.begin(), E = Results.end(); I != E; ++I)
183 I->print(OS);
184 break;
185 }
186
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000187 case PrintDefs: {
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000188 Analyz.FindDeclarations(D, Results);
189 for (ResultsTy::iterator
190 I = Results.begin(), E = Results.end(); I != E; ++I) {
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000191 const Decl *D = I->AsDecl();
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000192 bool isDef = false;
193 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
194 isDef = FD->isThisDeclarationADefinition();
195 else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
196 isDef = VD->getInit() != 0;
Argyrios Kyrtzidis87bcb502009-07-29 23:41:46 +0000197 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
198 isDef = MD->isThisDeclarationADefinition();
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000199
200 if (isDef)
201 I->print(OS);
202 }
203 break;
204 }
205
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000206 }
207}
208
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000209static llvm::cl::opt<bool>
210ASTFromSource("ast-from-source",
Daniel Dunbar7b556682009-12-02 03:23:45 +0000211 llvm::cl::desc("Treat the inputs as source files to parse"));
212
213static llvm::cl::list<std::string>
214CompilerArgs("arg", llvm::cl::desc("Extra arguments to use during parsing"));
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000215
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000216static llvm::cl::list<std::string>
217InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
218
Daniel Dunbar7b556682009-12-02 03:23:45 +0000219ASTUnit *CreateFromSource(const std::string &Filename, Diagnostic &Diags,
220 const char *Argv0) {
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000221 llvm::SmallVector<const char *, 16> Args;
222 Args.push_back(Filename.c_str());
Daniel Dunbar7b556682009-12-02 03:23:45 +0000223 for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
224 Args.push_back(CompilerArgs[i].c_str());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000225
Daniel Dunbar869824e2009-12-13 03:46:13 +0000226 void *MainAddr = (void*) (intptr_t) CreateFromSource;
227 llvm::sys::Path ResourcesPath(
228 CompilerInvocation::GetBuiltinIncludePath(Argv0, MainAddr));
229 ResourcesPath.eraseComponent();
Daniel Dunbar7b556682009-12-02 03:23:45 +0000230 return ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
Daniel Dunbar869824e2009-12-13 03:46:13 +0000231 Diags, ResourcesPath.str());
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000232}
233
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000234int main(int argc, char **argv) {
235 llvm::sys::PrintStackTraceOnErrorSignal();
236 llvm::PrettyStackTraceProgram X(argc, argv);
237 llvm::cl::ParseCommandLineOptions(argc, argv,
238 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
Mike Stump1eb44332009-09-09 15:08:12 +0000239
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000240 Program Prog;
Daniel Dunbara3907592009-09-21 03:03:22 +0000241 Indexer Idxer(Prog);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000242 llvm::SmallVector<TUnit*, 4> TUnits;
Mike Stump1eb44332009-09-09 15:08:12 +0000243
Daniel Dunbarbb3503a2009-12-06 09:56:30 +0000244 DiagnosticOptions DiagOpts;
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000245 llvm::OwningPtr<Diagnostic> Diags(
Daniel Dunbarbb3503a2009-12-06 09:56:30 +0000246 CompilerInstance::createDiagnostics(DiagOpts, argc, argv));
Daniel Dunbar521bf9c2009-12-01 09:51:01 +0000247
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000248 // If no input was specified, read from stdin.
249 if (InputFilenames.empty())
250 InputFilenames.push_back("-");
251
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000252 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
253 const std::string &InFile = InputFilenames[i];
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000254 llvm::OwningPtr<ASTUnit> AST;
Daniel Dunbar5262fda2009-12-03 01:45:44 +0000255 if (ASTFromSource)
Daniel Dunbar7b556682009-12-02 03:23:45 +0000256 AST.reset(CreateFromSource(InFile, *Diags, argv[0]));
Daniel Dunbar5262fda2009-12-03 01:45:44 +0000257 else
258 AST.reset(ASTUnit::LoadFromPCHFile(InFile, *Diags));
259 if (!AST)
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000260 return 1;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000261
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000262 TUnit *TU = new TUnit(AST.take(), InFile);
263 TUnits.push_back(TU);
Mike Stump1eb44332009-09-09 15:08:12 +0000264
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000265 Idxer.IndexAST(TU);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000266 }
267
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000268 ASTLocation ASTLoc;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000269 const std::string &FirstFile = TUnits[0]->Filename;
270 ASTUnit *FirstAST = TUnits[0]->AST.get();
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000271
272 if (!PointAtLocation.empty()) {
273 const std::string &Filename = PointAtLocation[0].FileName;
Steve Naroff36c44642009-10-19 14:34:22 +0000274 const FileEntry *File = FirstAST->getFileManager().getFile(Filename);
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000275 if (File == 0) {
276 llvm::errs() << "File '" << Filename << "' does not exist\n";
277 return 1;
278 }
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000279
280 // Safety check. Using an out-of-date AST file will only lead to crashes
281 // or incorrect results.
282 // FIXME: Check all the source files that make up the AST file.
Steve Naroff36c44642009-10-19 14:34:22 +0000283 const FileEntry *ASTFile = FirstAST->getFileManager().getFile(FirstFile);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000284 if (File->getModificationTime() > ASTFile->getModificationTime()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000285 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000286 "Pointing at a source file which was modified after creating "
287 "the AST file\n";
288 return 1;
289 }
290
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000291 unsigned Line = PointAtLocation[0].Line;
292 unsigned Col = PointAtLocation[0].Column;
293
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000294 SourceLocation Loc =
295 FirstAST->getSourceManager().getLocation(File, Line, Col);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000296 if (Loc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000297 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000298 "Couldn't resolve source location (invalid location)\n";
299 return 1;
300 }
Mike Stump1eb44332009-09-09 15:08:12 +0000301
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000302 ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
303 if (ASTLoc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000304 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000305 "Couldn't resolve source location (no declaration found)\n";
306 return 1;
307 }
308 }
Mike Stump1eb44332009-09-09 15:08:12 +0000309
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000310 if (ASTLoc.isValid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000311 if (ProgAction == PrintPoint) {
312 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000313 ASTLoc.print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000314 if (const char *Comment =
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000315 FirstAST->getASTContext().getCommentForDecl(ASTLoc.dyn_AsDecl()))
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000316 OS << "Comment associated with this declaration:\n" << Comment << "\n";
317 } else {
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000318 ProcessASTLocation(ASTLoc, Idxer);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000319 }
320 }
Mike Stump1eb44332009-09-09 15:08:12 +0000321
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000322 if (HadErrors)
323 return 1;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000324
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000325 if (!DisableFree) {
326 for (int i=0, e=TUnits.size(); i != e; ++i)
327 delete TUnits[i];
328 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000329
330 // Managed static deconstruction. Useful for making things like
331 // -time-passes usable.
332 llvm::llvm_shutdown();
Mike Stump1eb44332009-09-09 15:08:12 +0000333
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000334 return 0;
335}