blob: fce48edf26e081869ffbe1a637968c690ed448a4 [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"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000046#include "clang/Frontend/CommandLineSourceLoc.h"
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +000047#include "clang/AST/DeclObjC.h"
48#include "clang/AST/ExprObjC.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000049#include "clang/Basic/FileManager.h"
50#include "clang/Basic/SourceManager.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000051#include "llvm/Support/CommandLine.h"
52#include "llvm/Support/ManagedStatic.h"
53#include "llvm/Support/PrettyStackTrace.h"
54#include "llvm/Support/raw_ostream.h"
55#include "llvm/System/Signals.h"
56using namespace clang;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000057using namespace idx;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000058
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000059class TUnit : public TranslationUnit {
60public:
61 TUnit(ASTUnit *ast, const std::string &filename)
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000062 : AST(ast), Filename(filename),
63 DeclRefMap(ast->getASTContext()),
64 SelMap(ast->getASTContext()) { }
Mike Stump1eb44332009-09-09 15:08:12 +000065
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000066 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000067 virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000068 virtual SelectorMap &getSelectorMap() { return SelMap; }
Mike Stump1eb44332009-09-09 15:08:12 +000069
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000070 llvm::OwningPtr<ASTUnit> AST;
71 std::string Filename;
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000072 DeclReferenceMap DeclRefMap;
Argyrios Kyrtzidis0f398482009-07-29 23:41:08 +000073 SelectorMap SelMap;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000074};
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000075
76static llvm::cl::list<ParsedSourceLocation>
77PointAtLocation("point-at", llvm::cl::Optional,
78 llvm::cl::value_desc("source-location"),
79 llvm::cl::desc("Point at the given source location of the first AST file"));
80
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000081enum ProgActions {
82 PrintPoint, // Just print the point-at node
83 PrintRefs, // Print references of the point-at node
84 PrintDefs, // Print definitions of the point-at node
85 PrintDecls // Print declarations of the point-at node
86};
87
Mike Stump1eb44332009-09-09 15:08:12 +000088static llvm::cl::opt<ProgActions>
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000089ProgAction(
90 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
91 llvm::cl::ZeroOrMore,
92 llvm::cl::init(PrintPoint),
93 llvm::cl::values(
94 clEnumValN(PrintRefs, "print-refs",
95 "Print references"),
96 clEnumValN(PrintDefs, "print-defs",
97 "Print definitions"),
98 clEnumValN(PrintDecls, "print-decls",
99 "Print declarations"),
100 clEnumValEnd));
101
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000102static llvm::cl::opt<bool>
103DisableFree("disable-free",
104 llvm::cl::desc("Disable freeing of memory on exit"),
105 llvm::cl::init(false));
106
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000107static bool HadErrors = false;
108
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000109static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
110 llvm::raw_ostream &OS = llvm::outs();
111 typedef Storing<TULocationHandler> ResultsTy;
112 ResultsTy Results;
113
114 Analyzer Analyz(Idxer.getProgram(), Idxer);
115
116 switch (ProgAction) {
117 default: assert(0);
118 case PrintRefs:
119 llvm::errs() << "Error: Cannot -print-refs on a ObjC message expression\n";
120 HadErrors = true;
121 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000122
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000123 case PrintDecls: {
124 Analyz.FindObjCMethods(Msg, Results);
125 for (ResultsTy::iterator
126 I = Results.begin(), E = Results.end(); I != E; ++I)
127 I->print(OS);
128 break;
129 }
130
131 case PrintDefs: {
132 Analyz.FindObjCMethods(Msg, Results);
133 for (ResultsTy::iterator
134 I = Results.begin(), E = Results.end(); I != E; ++I) {
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000135 const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->AsDecl());
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000136 if (D->isThisDeclarationADefinition())
137 I->print(OS);
138 }
139 break;
140 }
141
142 }
143}
144
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000145static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000146 assert(ASTLoc.isValid());
Mike Stump1eb44332009-09-09 15:08:12 +0000147
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000148 if (ObjCMessageExpr *Msg =
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000149 dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.dyn_AsStmt()))
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000150 return ProcessObjCMessage(Msg, Idxer);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000151
Argyrios Kyrtzidisdc50c642009-07-18 21:17:58 +0000152 Decl *D = ASTLoc.getReferencedDecl();
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000153 if (D == 0) {
Argyrios Kyrtzidisec930d32009-07-21 00:05:10 +0000154 llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000155 HadErrors = true;
156 return;
157 }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000158
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000159 llvm::raw_ostream &OS = llvm::outs();
160 typedef Storing<TULocationHandler> ResultsTy;
161 ResultsTy Results;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000162
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000163 Analyzer Analyz(Idxer.getProgram(), Idxer);
Argyrios Kyrtzidis94431b52009-07-29 23:39:03 +0000164
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000165 switch (ProgAction) {
166 default: assert(0);
167 case PrintRefs: {
168 Analyz.FindReferences(D, Results);
169 for (ResultsTy::iterator
170 I = Results.begin(), E = Results.end(); I != E; ++I)
171 I->print(OS);
172 break;
173 }
174
175 case PrintDecls: {
176 Analyz.FindDeclarations(D, Results);
177 for (ResultsTy::iterator
178 I = Results.begin(), E = Results.end(); I != E; ++I)
179 I->print(OS);
180 break;
181 }
182
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000183 case PrintDefs: {
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000184 Analyz.FindDeclarations(D, Results);
185 for (ResultsTy::iterator
186 I = Results.begin(), E = Results.end(); I != E; ++I) {
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000187 const Decl *D = I->AsDecl();
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000188 bool isDef = false;
189 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
190 isDef = FD->isThisDeclarationADefinition();
191 else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
192 isDef = VD->getInit() != 0;
Argyrios Kyrtzidis87bcb502009-07-29 23:41:46 +0000193 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
194 isDef = MD->isThisDeclarationADefinition();
Argyrios Kyrtzidis7f4656e2009-07-29 23:40:14 +0000195
196 if (isDef)
197 I->print(OS);
198 }
199 break;
200 }
201
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000202 }
203}
204
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000205static llvm::cl::list<std::string>
206InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
207
208int main(int argc, char **argv) {
209 llvm::sys::PrintStackTraceOnErrorSignal();
210 llvm::PrettyStackTraceProgram X(argc, argv);
211 llvm::cl::ParseCommandLineOptions(argc, argv,
212 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
Mike Stump1eb44332009-09-09 15:08:12 +0000213
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000214 Program Prog;
Daniel Dunbara3907592009-09-21 03:03:22 +0000215 Indexer Idxer(Prog);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000216 llvm::SmallVector<TUnit*, 4> TUnits;
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000218 // If no input was specified, read from stdin.
219 if (InputFilenames.empty())
220 InputFilenames.push_back("-");
221
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000222 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
223 const std::string &InFile = InputFilenames[i];
Mike Stump1eb44332009-09-09 15:08:12 +0000224
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000225 std::string ErrMsg;
226 llvm::OwningPtr<ASTUnit> AST;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000227
Steve Naroff36c44642009-10-19 14:34:22 +0000228 AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000229 if (!AST) {
230 llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
231 return 1;
232 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000233
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000234 TUnit *TU = new TUnit(AST.take(), InFile);
235 TUnits.push_back(TU);
Mike Stump1eb44332009-09-09 15:08:12 +0000236
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000237 Idxer.IndexAST(TU);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000238 }
239
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000240 ASTLocation ASTLoc;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000241 const std::string &FirstFile = TUnits[0]->Filename;
242 ASTUnit *FirstAST = TUnits[0]->AST.get();
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000243
244 if (!PointAtLocation.empty()) {
245 const std::string &Filename = PointAtLocation[0].FileName;
Steve Naroff36c44642009-10-19 14:34:22 +0000246 const FileEntry *File = FirstAST->getFileManager().getFile(Filename);
Argyrios Kyrtzidis19b732a2009-07-30 00:03:55 +0000247 if (File == 0) {
248 llvm::errs() << "File '" << Filename << "' does not exist\n";
249 return 1;
250 }
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000251
252 // Safety check. Using an out-of-date AST file will only lead to crashes
253 // or incorrect results.
254 // FIXME: Check all the source files that make up the AST file.
Steve Naroff36c44642009-10-19 14:34:22 +0000255 const FileEntry *ASTFile = FirstAST->getFileManager().getFile(FirstFile);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000256 if (File->getModificationTime() > ASTFile->getModificationTime()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000257 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000258 "Pointing at a source file which was modified after creating "
259 "the AST file\n";
260 return 1;
261 }
262
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000263 unsigned Line = PointAtLocation[0].Line;
264 unsigned Col = PointAtLocation[0].Column;
265
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000266 SourceLocation Loc =
267 FirstAST->getSourceManager().getLocation(File, Line, Col);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000268 if (Loc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000269 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000270 "Couldn't resolve source location (invalid location)\n";
271 return 1;
272 }
Mike Stump1eb44332009-09-09 15:08:12 +0000273
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000274 ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
275 if (ASTLoc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000276 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000277 "Couldn't resolve source location (no declaration found)\n";
278 return 1;
279 }
280 }
Mike Stump1eb44332009-09-09 15:08:12 +0000281
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000282 if (ASTLoc.isValid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000283 if (ProgAction == PrintPoint) {
284 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000285 ASTLoc.print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000286 if (const char *Comment =
Argyrios Kyrtzidisf4526e32009-09-29 19:44:27 +0000287 FirstAST->getASTContext().getCommentForDecl(ASTLoc.dyn_AsDecl()))
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000288 OS << "Comment associated with this declaration:\n" << Comment << "\n";
289 } else {
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000290 ProcessASTLocation(ASTLoc, Idxer);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000291 }
292 }
Mike Stump1eb44332009-09-09 15:08:12 +0000293
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000294 if (HadErrors)
295 return 1;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000296
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000297 if (!DisableFree) {
298 for (int i=0, e=TUnits.size(); i != e; ++i)
299 delete TUnits[i];
300 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000301
302 // Managed static deconstruction. Useful for making things like
303 // -time-passes usable.
304 llvm::llvm_shutdown();
Mike Stump1eb44332009-09-09 15:08:12 +0000305
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000306 return 0;
307}