blob: a188cd103ed8bc951dffcdde07cef8493531af1d [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"
36#include "clang/Index/IndexProvider.h"
37#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 Kyrtzidis818e15b2009-07-06 21:35:02 +000041#include "clang/Index/Utils.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000042#include "clang/Frontend/ASTUnit.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000043#include "clang/Frontend/CommandLineSourceLoc.h"
44#include "clang/AST/Decl.h"
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000045#include "clang/AST/Expr.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000046#include "clang/Basic/FileManager.h"
47#include "clang/Basic/SourceManager.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000048#include "llvm/Support/CommandLine.h"
49#include "llvm/Support/ManagedStatic.h"
50#include "llvm/Support/PrettyStackTrace.h"
51#include "llvm/Support/raw_ostream.h"
52#include "llvm/System/Signals.h"
53using namespace clang;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000054using namespace idx;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000055
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000056class TUnit : public TranslationUnit {
57public:
58 TUnit(ASTUnit *ast, const std::string &filename)
59 : AST(ast), Filename(filename) { }
60
61 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
62
63 llvm::OwningPtr<ASTUnit> AST;
64 std::string Filename;
65};
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000066
67static llvm::cl::list<ParsedSourceLocation>
68PointAtLocation("point-at", llvm::cl::Optional,
69 llvm::cl::value_desc("source-location"),
70 llvm::cl::desc("Point at the given source location of the first AST file"));
71
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000072enum ProgActions {
73 PrintPoint, // Just print the point-at node
74 PrintRefs, // Print references of the point-at node
75 PrintDefs, // Print definitions of the point-at node
76 PrintDecls // Print declarations of the point-at node
77};
78
79static llvm::cl::opt<ProgActions>
80ProgAction(
81 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
82 llvm::cl::ZeroOrMore,
83 llvm::cl::init(PrintPoint),
84 llvm::cl::values(
85 clEnumValN(PrintRefs, "print-refs",
86 "Print references"),
87 clEnumValN(PrintDefs, "print-defs",
88 "Print definitions"),
89 clEnumValN(PrintDecls, "print-decls",
90 "Print declarations"),
91 clEnumValEnd));
92
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000093static llvm::cl::opt<bool>
94DisableFree("disable-free",
95 llvm::cl::desc("Disable freeing of memory on exit"),
96 llvm::cl::init(false));
97
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +000098static bool HadErrors = false;
99
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000100static void ProcessDecl(Decl *D) {
101 assert(D);
102 llvm::raw_ostream &OS = llvm::outs();
103
104 switch (ProgAction) {
105 default: assert(0);
106 case PrintRefs: {
107 NamedDecl *ND = dyn_cast<NamedDecl>(D);
108 if (!ND)
109 return;
110
111 DeclReferenceMap RefMap(ND->getASTContext());
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000112 for (DeclReferenceMap::astlocation_iterator
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000113 I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
114 I->print(OS);
115 break;
116 }
117
118 case PrintDefs: {
119 const Decl *DefD = 0;
120 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
121 const FunctionDecl *DFD = 0;
122 FD->getBody(DFD);
123 DefD = DFD;
124 } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
125 const VarDecl *DVD = 0;
126 VD->getDefinition(DVD);
127 DefD = DVD;
128 }
129
130 if (DefD)
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000131 ASTLocation(DefD).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000132 break;
133 }
134
135 case PrintDecls :
136 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Argyrios Kyrtzidisc7377632009-07-14 03:20:31 +0000137 for (FunctionDecl::redecl_iterator I = FD->redecls_begin(),
138 E = FD->redecls_end(); I != E; ++I)
139 ASTLocation(*I).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000140 } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
Argyrios Kyrtzidisc7377632009-07-14 03:20:31 +0000141 for (VarDecl::redecl_iterator I = VD->redecls_begin(),
142 E = VD->redecls_end(); I != E; ++I)
143 ASTLocation(*I).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000144 } else
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000145 ASTLocation(D).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000146 break;
147
148 }
149}
150
Argyrios Kyrtzidisbe125442009-07-14 03:19:30 +0000151static Decl *getDeclFromExpr(Stmt *E) {
152 if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
153 return RefExpr->getDecl();
154 if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
155 return ME->getMemberDecl();
156 if (CallExpr *CE = dyn_cast<CallExpr>(E))
157 return getDeclFromExpr(CE->getCallee());
158 if (CastExpr *CE = dyn_cast<CastExpr>(E))
159 return getDeclFromExpr(CE->getSubExpr());
160
161 return 0;
162}
163
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000164static void ProcessASTLocation(ASTLocation ASTLoc, IndexProvider &IdxProvider) {
165 assert(ASTLoc.isValid());
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000166
167 Decl *D = 0;
Argyrios Kyrtzidisbe125442009-07-14 03:19:30 +0000168 if (ASTLoc.isStmt())
169 D = getDeclFromExpr(ASTLoc.getStmt());
170 else
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000171 D = ASTLoc.getDecl();
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000172
173 if (D == 0) {
174 llvm::errs() << "Error: Couldn't get a Decl out of the ASTLocation";
175 HadErrors = true;
176 return;
177 }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000178
179 Entity *Ent = Entity::get(D, IdxProvider.getProgram());
180 // If there is no Entity associated with this Decl, it means that it's not
181 // visible to other translation units.
182 if (!Ent)
183 return ProcessDecl(D);
184
185 // Find the "same" Decl in other translation units and print information.
186 for (IndexProvider::translation_unit_iterator
187 I = IdxProvider.translation_units_begin(Ent),
188 E = IdxProvider.translation_units_end(Ent); I != E; ++I) {
189 TUnit *TU = static_cast<TUnit*>(*I);
190 Decl *OtherD = Ent->getDecl(TU->getASTContext());
191 assert(OtherD && "Couldn't resolve Entity");
192 ProcessDecl(OtherD);
193 }
194}
195
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000196static llvm::cl::list<std::string>
197InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
198
199int main(int argc, char **argv) {
200 llvm::sys::PrintStackTraceOnErrorSignal();
201 llvm::PrettyStackTraceProgram X(argc, argv);
202 llvm::cl::ParseCommandLineOptions(argc, argv,
203 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
204
205 FileManager FileMgr;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000206
207 Program Prog;
208 IndexProvider IdxProvider(Prog);
209 llvm::SmallVector<TUnit*, 4> TUnits;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000210
211 // If no input was specified, read from stdin.
212 if (InputFilenames.empty())
213 InputFilenames.push_back("-");
214
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000215 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
216 const std::string &InFile = InputFilenames[i];
217
218 std::string ErrMsg;
219 llvm::OwningPtr<ASTUnit> AST;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000220
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000221 AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
222 if (!AST) {
223 llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
224 return 1;
225 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000226
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000227 TUnit *TU = new TUnit(AST.take(), InFile);
228 TUnits.push_back(TU);
229
230 IdxProvider.IndexAST(TU);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000231 }
232
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000233 ASTLocation ASTLoc;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000234 const std::string &FirstFile = TUnits[0]->Filename;
235 ASTUnit *FirstAST = TUnits[0]->AST.get();
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000236
237 if (!PointAtLocation.empty()) {
238 const std::string &Filename = PointAtLocation[0].FileName;
239 const FileEntry *File = FileMgr.getFile(Filename);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000240
241 // Safety check. Using an out-of-date AST file will only lead to crashes
242 // or incorrect results.
243 // FIXME: Check all the source files that make up the AST file.
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000244 const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000245 if (File->getModificationTime() > ASTFile->getModificationTime()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000246 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000247 "Pointing at a source file which was modified after creating "
248 "the AST file\n";
249 return 1;
250 }
251
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000252 if (File == 0) {
253 llvm::errs() << "File '" << Filename << "' does not exist\n";
254 return 1;
255 }
256 unsigned Line = PointAtLocation[0].Line;
257 unsigned Col = PointAtLocation[0].Column;
258
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000259 SourceLocation Loc =
260 FirstAST->getSourceManager().getLocation(File, Line, Col);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000261 if (Loc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000262 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000263 "Couldn't resolve source location (invalid location)\n";
264 return 1;
265 }
266
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000267 ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
268 if (ASTLoc.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 (no declaration found)\n";
271 return 1;
272 }
273 }
274
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000275 if (ASTLoc.isValid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000276 if (ProgAction == PrintPoint) {
277 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000278 ASTLoc.print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000279 if (const char *Comment =
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000280 FirstAST->getASTContext().getCommentForDecl(ASTLoc.getDecl()))
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000281 OS << "Comment associated with this declaration:\n" << Comment << "\n";
282 } else {
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000283 ProcessASTLocation(ASTLoc, IdxProvider);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000284 }
285 }
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000286
287 if (HadErrors)
288 return 1;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000289
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000290 if (!DisableFree) {
291 for (int i=0, e=TUnits.size(); i != e; ++i)
292 delete TUnits[i];
293 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000294
295 // Managed static deconstruction. Useful for making things like
296 // -time-passes usable.
297 llvm::llvm_shutdown();
298
299 return 0;
300}