blob: 5fc6269f7a8f0b043587fc59ca156d690e3ed449 [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 Kyrtzidis94431b52009-07-29 23:39:03 +000041#include "clang/Index/Handlers.h"
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000042#include "clang/Index/Utils.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000043#include "clang/Frontend/ASTUnit.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000044#include "clang/Frontend/CommandLineSourceLoc.h"
45#include "clang/AST/Decl.h"
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000046#include "clang/AST/Expr.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000047#include "clang/Basic/FileManager.h"
48#include "clang/Basic/SourceManager.h"
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000049#include "llvm/Support/CommandLine.h"
50#include "llvm/Support/ManagedStatic.h"
51#include "llvm/Support/PrettyStackTrace.h"
52#include "llvm/Support/raw_ostream.h"
53#include "llvm/System/Signals.h"
54using namespace clang;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000055using namespace idx;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000056
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000057class TUnit : public TranslationUnit {
58public:
59 TUnit(ASTUnit *ast, const std::string &filename)
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000060 : AST(ast), Filename(filename), DeclRefMap(ast->getASTContext()) { }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000061
62 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000063 virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000064
65 llvm::OwningPtr<ASTUnit> AST;
66 std::string Filename;
Argyrios Kyrtzidis768a6c92009-07-29 23:39:18 +000067 DeclReferenceMap DeclRefMap;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000068};
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000069
70static llvm::cl::list<ParsedSourceLocation>
71PointAtLocation("point-at", llvm::cl::Optional,
72 llvm::cl::value_desc("source-location"),
73 llvm::cl::desc("Point at the given source location of the first AST file"));
74
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +000075enum ProgActions {
76 PrintPoint, // Just print the point-at node
77 PrintRefs, // Print references of the point-at node
78 PrintDefs, // Print definitions of the point-at node
79 PrintDecls // Print declarations of the point-at node
80};
81
82static llvm::cl::opt<ProgActions>
83ProgAction(
84 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
85 llvm::cl::ZeroOrMore,
86 llvm::cl::init(PrintPoint),
87 llvm::cl::values(
88 clEnumValN(PrintRefs, "print-refs",
89 "Print references"),
90 clEnumValN(PrintDefs, "print-defs",
91 "Print definitions"),
92 clEnumValN(PrintDecls, "print-decls",
93 "Print declarations"),
94 clEnumValEnd));
95
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +000096static llvm::cl::opt<bool>
97DisableFree("disable-free",
98 llvm::cl::desc("Disable freeing of memory on exit"),
99 llvm::cl::init(false));
100
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000101static bool HadErrors = false;
102
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000103static void ProcessDecl(Decl *D) {
104 assert(D);
105 llvm::raw_ostream &OS = llvm::outs();
106
107 switch (ProgAction) {
108 default: assert(0);
109 case PrintRefs: {
110 NamedDecl *ND = dyn_cast<NamedDecl>(D);
111 if (!ND)
112 return;
113
114 DeclReferenceMap RefMap(ND->getASTContext());
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000115 for (DeclReferenceMap::astlocation_iterator
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000116 I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
117 I->print(OS);
118 break;
119 }
120
121 case PrintDefs: {
122 const Decl *DefD = 0;
123 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
124 const FunctionDecl *DFD = 0;
125 FD->getBody(DFD);
126 DefD = DFD;
127 } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
128 const VarDecl *DVD = 0;
129 VD->getDefinition(DVD);
130 DefD = DVD;
131 }
132
133 if (DefD)
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000134 ASTLocation(DefD).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000135 break;
136 }
137
138 case PrintDecls :
Argyrios Kyrtzidis1e4bc092009-07-18 08:50:35 +0000139 for (Decl::redecl_iterator I = D->redecls_begin(),
140 E = D->redecls_end(); I != E; ++I)
141 ASTLocation(*I).print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000142 break;
143
144 }
145}
146
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000147static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000148 assert(ASTLoc.isValid());
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000149
Argyrios Kyrtzidisdc50c642009-07-18 21:17:58 +0000150 Decl *D = ASTLoc.getReferencedDecl();
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000151 if (D == 0) {
Argyrios Kyrtzidisec930d32009-07-21 00:05:10 +0000152 llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000153 HadErrors = true;
154 return;
155 }
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000156
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000157 Entity Ent = Entity::get(D, Idxer.getProgram());
Argyrios Kyrtzidisf7cf15c2009-07-21 00:07:06 +0000158 if (Ent.isInvalid() || Ent.isInternalToTU())
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000159 return ProcessDecl(D);
160
Argyrios Kyrtzidis94431b52009-07-29 23:39:03 +0000161 Storing<TranslationUnitHandler> TURes;
162 Idxer.GetTranslationUnitsFor(Ent, TURes);
163
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000164 // Find the "same" Decl in other translation units and print information.
Argyrios Kyrtzidis94431b52009-07-29 23:39:03 +0000165 for (Storing<TranslationUnitHandler>::iterator
166 I = TURes.begin(), E = TURes.end(); I != E; ++I) {
167 Decl *OtherD = Ent.getDecl((*I)->getASTContext());
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000168 assert(OtherD && "Couldn't resolve Entity");
169 ProcessDecl(OtherD);
170 }
171}
172
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000173static llvm::cl::list<std::string>
174InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
175
176int main(int argc, char **argv) {
177 llvm::sys::PrintStackTraceOnErrorSignal();
178 llvm::PrettyStackTraceProgram X(argc, argv);
179 llvm::cl::ParseCommandLineOptions(argc, argv,
180 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
181
182 FileManager FileMgr;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000183
184 Program Prog;
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000185 Indexer Idxer(Prog);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000186 llvm::SmallVector<TUnit*, 4> TUnits;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000187
188 // If no input was specified, read from stdin.
189 if (InputFilenames.empty())
190 InputFilenames.push_back("-");
191
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000192 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
193 const std::string &InFile = InputFilenames[i];
194
195 std::string ErrMsg;
196 llvm::OwningPtr<ASTUnit> AST;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000197
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000198 AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
199 if (!AST) {
200 llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
201 return 1;
202 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000203
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000204 TUnit *TU = new TUnit(AST.take(), InFile);
205 TUnits.push_back(TU);
206
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000207 Idxer.IndexAST(TU);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000208 }
209
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000210 ASTLocation ASTLoc;
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000211 const std::string &FirstFile = TUnits[0]->Filename;
212 ASTUnit *FirstAST = TUnits[0]->AST.get();
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000213
214 if (!PointAtLocation.empty()) {
215 const std::string &Filename = PointAtLocation[0].FileName;
216 const FileEntry *File = FileMgr.getFile(Filename);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000217
218 // Safety check. Using an out-of-date AST file will only lead to crashes
219 // or incorrect results.
220 // FIXME: Check all the source files that make up the AST file.
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000221 const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000222 if (File->getModificationTime() > ASTFile->getModificationTime()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000223 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis119b7fe2009-06-25 22:15:12 +0000224 "Pointing at a source file which was modified after creating "
225 "the AST file\n";
226 return 1;
227 }
228
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000229 if (File == 0) {
230 llvm::errs() << "File '" << Filename << "' does not exist\n";
231 return 1;
232 }
233 unsigned Line = PointAtLocation[0].Line;
234 unsigned Col = PointAtLocation[0].Column;
235
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000236 SourceLocation Loc =
237 FirstAST->getSourceManager().getLocation(File, Line, Col);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000238 if (Loc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000239 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000240 "Couldn't resolve source location (invalid location)\n";
241 return 1;
242 }
243
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000244 ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
245 if (ASTLoc.isInvalid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000246 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000247 "Couldn't resolve source location (no declaration found)\n";
248 return 1;
249 }
250 }
251
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000252 if (ASTLoc.isValid()) {
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000253 if (ProgAction == PrintPoint) {
254 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000255 ASTLoc.print(OS);
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000256 if (const char *Comment =
Argyrios Kyrtzidis44994052009-07-06 21:35:26 +0000257 FirstAST->getASTContext().getCommentForDecl(ASTLoc.getDecl()))
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000258 OS << "Comment associated with this declaration:\n" << Comment << "\n";
259 } else {
Argyrios Kyrtzidisb17dc462009-07-29 23:38:21 +0000260 ProcessASTLocation(ASTLoc, Idxer);
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000261 }
262 }
Argyrios Kyrtzidis12585542009-07-14 03:18:40 +0000263
264 if (HadErrors)
265 return 1;
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000266
Argyrios Kyrtzidis7b332d92009-07-05 22:22:35 +0000267 if (!DisableFree) {
268 for (int i=0, e=TUnits.size(); i != e; ++i)
269 delete TUnits[i];
270 }
Argyrios Kyrtzidis30b983b2009-06-25 18:22:52 +0000271
272 // Managed static deconstruction. Useful for making things like
273 // -time-passes usable.
274 llvm::llvm_shutdown();
275
276 return 0;
277}