blob: a0d60f7b492238962a8f28cf87acd45acf35c9ff [file] [log] [blame]
Argiris Kirtzidis23d23232009-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 Xu66281392009-07-07 07:14:55 +000020// -point-at [file:line:column]
Argiris Kirtzidis8a37ea02009-06-25 21:54:50 +000021// Point at a declaration/statement/expression. If no other operation is
22// specified, prints some info about it.
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000023//
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000024// -print-refs
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +000025// Print ASTLocations that reference the -point-at node
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000026//
27// -print-defs
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +000028// Print ASTLocations that define the -point-at node
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000029//
30// -print-decls
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +000031// Print ASTLocations that declare the -point-at node
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000032//
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000033//===----------------------------------------------------------------------===//
34
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000035#include "clang/Index/Program.h"
Argiris Kirtzidis43d4f2e2009-07-29 23:38:21 +000036#include "clang/Index/Indexer.h"
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000037#include "clang/Index/Entity.h"
38#include "clang/Index/TranslationUnit.h"
Argiris Kirtzidis75abd9c2009-07-06 21:34:47 +000039#include "clang/Index/ASTLocation.h"
40#include "clang/Index/DeclReferenceMap.h"
Argiris Kirtzidis915949f2009-07-29 23:39:03 +000041#include "clang/Index/Handlers.h"
Argiris Kirtzidis9928abb2009-07-29 23:40:14 +000042#include "clang/Index/Analyzer.h"
Argiris Kirtzidis98eec712009-07-06 21:35:02 +000043#include "clang/Index/Utils.h"
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000044#include "clang/Frontend/ASTUnit.h"
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000045#include "clang/Frontend/CommandLineSourceLoc.h"
46#include "clang/AST/Decl.h"
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000047#include "clang/AST/Expr.h"
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000048#include "clang/Basic/FileManager.h"
49#include "clang/Basic/SourceManager.h"
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000050#include "llvm/Support/CommandLine.h"
51#include "llvm/Support/ManagedStatic.h"
52#include "llvm/Support/PrettyStackTrace.h"
53#include "llvm/Support/raw_ostream.h"
54#include "llvm/System/Signals.h"
55using namespace clang;
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000056using namespace idx;
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000057
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000058class TUnit : public TranslationUnit {
59public:
60 TUnit(ASTUnit *ast, const std::string &filename)
Argiris Kirtzidisc39d6492009-07-29 23:39:18 +000061 : AST(ast), Filename(filename), DeclRefMap(ast->getASTContext()) { }
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000062
63 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
Argiris Kirtzidisc39d6492009-07-29 23:39:18 +000064 virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000065
66 llvm::OwningPtr<ASTUnit> AST;
67 std::string Filename;
Argiris Kirtzidisc39d6492009-07-29 23:39:18 +000068 DeclReferenceMap DeclRefMap;
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000069};
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000070
71static llvm::cl::list<ParsedSourceLocation>
72PointAtLocation("point-at", llvm::cl::Optional,
73 llvm::cl::value_desc("source-location"),
74 llvm::cl::desc("Point at the given source location of the first AST file"));
75
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +000076enum ProgActions {
77 PrintPoint, // Just print the point-at node
78 PrintRefs, // Print references of the point-at node
79 PrintDefs, // Print definitions of the point-at node
80 PrintDecls // Print declarations of the point-at node
81};
82
83static llvm::cl::opt<ProgActions>
84ProgAction(
85 llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
86 llvm::cl::ZeroOrMore,
87 llvm::cl::init(PrintPoint),
88 llvm::cl::values(
89 clEnumValN(PrintRefs, "print-refs",
90 "Print references"),
91 clEnumValN(PrintDefs, "print-defs",
92 "Print definitions"),
93 clEnumValN(PrintDecls, "print-decls",
94 "Print declarations"),
95 clEnumValEnd));
96
Argiris Kirtzidis23d23232009-06-25 18:22:52 +000097static llvm::cl::opt<bool>
98DisableFree("disable-free",
99 llvm::cl::desc("Disable freeing of memory on exit"),
100 llvm::cl::init(false));
101
Argiris Kirtzidis8eb9fef2009-07-14 03:18:40 +0000102static bool HadErrors = false;
103
Argiris Kirtzidis43d4f2e2009-07-29 23:38:21 +0000104static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000105 assert(ASTLoc.isValid());
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000106
Argiris Kirtzidisec635572009-07-18 21:17:58 +0000107 Decl *D = ASTLoc.getReferencedDecl();
Argiris Kirtzidis8eb9fef2009-07-14 03:18:40 +0000108 if (D == 0) {
Argiris Kirtzidis3aefbf22009-07-21 00:05:10 +0000109 llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
Argiris Kirtzidis8eb9fef2009-07-14 03:18:40 +0000110 HadErrors = true;
111 return;
112 }
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000113
Argiris Kirtzidis9928abb2009-07-29 23:40:14 +0000114 llvm::raw_ostream &OS = llvm::outs();
115 typedef Storing<TULocationHandler> ResultsTy;
116 ResultsTy Results;
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000117
Argiris Kirtzidis9928abb2009-07-29 23:40:14 +0000118 Analyzer Analyz(Idxer.getProgram(), Idxer);
Argiris Kirtzidis915949f2009-07-29 23:39:03 +0000119
Argiris Kirtzidis9928abb2009-07-29 23:40:14 +0000120 switch (ProgAction) {
121 default: assert(0);
122 case PrintRefs: {
123 Analyz.FindReferences(D, Results);
124 for (ResultsTy::iterator
125 I = Results.begin(), E = Results.end(); I != E; ++I)
126 I->print(OS);
127 break;
128 }
129
130 case PrintDecls: {
131 Analyz.FindDeclarations(D, Results);
132 for (ResultsTy::iterator
133 I = Results.begin(), E = Results.end(); I != E; ++I)
134 I->print(OS);
135 break;
136 }
137
138 case PrintDefs:{
139 Analyz.FindDeclarations(D, Results);
140 for (ResultsTy::iterator
141 I = Results.begin(), E = Results.end(); I != E; ++I) {
142 const Decl *D = I->getDecl();
143 bool isDef = false;
144 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
145 isDef = FD->isThisDeclarationADefinition();
146 else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
147 isDef = VD->getInit() != 0;
148
149 if (isDef)
150 I->print(OS);
151 }
152 break;
153 }
154
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000155 }
156}
157
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000158static llvm::cl::list<std::string>
159InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
160
161int main(int argc, char **argv) {
162 llvm::sys::PrintStackTraceOnErrorSignal();
163 llvm::PrettyStackTraceProgram X(argc, argv);
164 llvm::cl::ParseCommandLineOptions(argc, argv,
165 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
166
167 FileManager FileMgr;
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000168
169 Program Prog;
Argiris Kirtzidis43d4f2e2009-07-29 23:38:21 +0000170 Indexer Idxer(Prog);
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000171 llvm::SmallVector<TUnit*, 4> TUnits;
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000172
173 // If no input was specified, read from stdin.
174 if (InputFilenames.empty())
175 InputFilenames.push_back("-");
176
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000177 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
178 const std::string &InFile = InputFilenames[i];
179
180 std::string ErrMsg;
181 llvm::OwningPtr<ASTUnit> AST;
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000182
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000183 AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
184 if (!AST) {
185 llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
186 return 1;
187 }
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000188
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000189 TUnit *TU = new TUnit(AST.take(), InFile);
190 TUnits.push_back(TU);
191
Argiris Kirtzidis43d4f2e2009-07-29 23:38:21 +0000192 Idxer.IndexAST(TU);
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000193 }
194
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000195 ASTLocation ASTLoc;
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000196 const std::string &FirstFile = TUnits[0]->Filename;
197 ASTUnit *FirstAST = TUnits[0]->AST.get();
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000198
199 if (!PointAtLocation.empty()) {
200 const std::string &Filename = PointAtLocation[0].FileName;
201 const FileEntry *File = FileMgr.getFile(Filename);
Argiris Kirtzidis01ae6822009-06-25 22:15:12 +0000202
203 // Safety check. Using an out-of-date AST file will only lead to crashes
204 // or incorrect results.
205 // FIXME: Check all the source files that make up the AST file.
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000206 const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
Argiris Kirtzidis01ae6822009-06-25 22:15:12 +0000207 if (File->getModificationTime() > ASTFile->getModificationTime()) {
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000208 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argiris Kirtzidis01ae6822009-06-25 22:15:12 +0000209 "Pointing at a source file which was modified after creating "
210 "the AST file\n";
211 return 1;
212 }
213
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000214 if (File == 0) {
215 llvm::errs() << "File '" << Filename << "' does not exist\n";
216 return 1;
217 }
218 unsigned Line = PointAtLocation[0].Line;
219 unsigned Col = PointAtLocation[0].Column;
220
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000221 SourceLocation Loc =
222 FirstAST->getSourceManager().getLocation(File, Line, Col);
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000223 if (Loc.isInvalid()) {
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000224 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000225 "Couldn't resolve source location (invalid location)\n";
226 return 1;
227 }
228
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000229 ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
230 if (ASTLoc.isInvalid()) {
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000231 llvm::errs() << "[" << FirstFile << "] Error: " <<
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000232 "Couldn't resolve source location (no declaration found)\n";
233 return 1;
234 }
235 }
236
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000237 if (ASTLoc.isValid()) {
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000238 if (ProgAction == PrintPoint) {
239 llvm::raw_ostream &OS = llvm::outs();
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000240 ASTLoc.print(OS);
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000241 if (const char *Comment =
Argiris Kirtzidisc59d2282009-07-06 21:35:26 +0000242 FirstAST->getASTContext().getCommentForDecl(ASTLoc.getDecl()))
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000243 OS << "Comment associated with this declaration:\n" << Comment << "\n";
244 } else {
Argiris Kirtzidis43d4f2e2009-07-29 23:38:21 +0000245 ProcessASTLocation(ASTLoc, Idxer);
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000246 }
247 }
Argiris Kirtzidis8eb9fef2009-07-14 03:18:40 +0000248
249 if (HadErrors)
250 return 1;
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000251
Argiris Kirtzidis9975cb42009-07-05 22:22:35 +0000252 if (!DisableFree) {
253 for (int i=0, e=TUnits.size(); i != e; ++i)
254 delete TUnits[i];
255 }
Argiris Kirtzidis23d23232009-06-25 18:22:52 +0000256
257 // Managed static deconstruction. Useful for making things like
258 // -time-passes usable.
259 llvm::llvm_shutdown();
260
261 return 0;
262}