Move the 'ResolveLocationInAST' function from the Frontend library to the Index library.
[clang.git] / tools / index-test / index-test.cpp
blob37ecbd928f32d5937460f94a4201d01eee9bfe9d
1 //===--- 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.
16 // Files must be AST files.
18 //===----------------------------------------------------------------------===//
20 // -point-at [file:column:line]
21 // Point at a declaration/statement/expression. If no other operation is
22 // specified, prints some info about it.
24 // -print-refs
25 // Print ASTLocations that reference the -point-at node
27 // -print-defs
28 // Print ASTLocations that define the -point-at node
30 // -print-decls
31 // Print ASTLocations that declare the -point-at node
33 //===----------------------------------------------------------------------===//
35 #include "clang/Index/Program.h"
36 #include "clang/Index/IndexProvider.h"
37 #include "clang/Index/Entity.h"
38 #include "clang/Index/TranslationUnit.h"
39 #include "clang/Index/ASTLocation.h"
40 #include "clang/Index/DeclReferenceMap.h"
41 #include "clang/Index/Utils.h"
42 #include "clang/Frontend/ASTUnit.h"
43 #include "clang/Frontend/CommandLineSourceLoc.h"
44 #include "clang/AST/Decl.h"
45 #include "clang/AST/Expr.h"
46 #include "clang/Basic/FileManager.h"
47 #include "clang/Basic/SourceManager.h"
48 #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"
53 using namespace clang;
54 using namespace idx;
56 class TUnit : public TranslationUnit {
57 public:
58 TUnit(ASTUnit *ast, const std::string &filename)
59 : AST(ast), Filename(filename) { }
61 virtual ASTContext &getASTContext() { return AST->getASTContext(); }
63 llvm::OwningPtr<ASTUnit> AST;
64 std::string Filename;
67 static llvm::cl::list<ParsedSourceLocation>
68 PointAtLocation("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"));
72 enum 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
79 static llvm::cl::opt<ProgActions>
80 ProgAction(
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));
93 static llvm::cl::opt<bool>
94 DisableFree("disable-free",
95 llvm::cl::desc("Disable freeing of memory on exit"),
96 llvm::cl::init(false));
98 static void ProcessDecl(Decl *D) {
99 assert(D);
100 llvm::raw_ostream &OS = llvm::outs();
102 switch (ProgAction) {
103 default: assert(0);
104 case PrintRefs: {
105 NamedDecl *ND = dyn_cast<NamedDecl>(D);
106 if (!ND)
107 return;
109 DeclReferenceMap RefMap(ND->getASTContext());
110 for (DeclReferenceMap::astlocation_iterator
111 I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
112 I->print(OS);
113 break;
116 case PrintDefs: {
117 const Decl *DefD = 0;
118 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
119 const FunctionDecl *DFD = 0;
120 FD->getBody(DFD);
121 DefD = DFD;
122 } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
123 const VarDecl *DVD = 0;
124 VD->getDefinition(DVD);
125 DefD = DVD;
128 if (DefD)
129 ASTLocation(DefD).print(OS);
130 break;
133 case PrintDecls :
134 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
135 while (FD) {
136 ASTLocation(FD).print(OS);
137 FD = FD->getPreviousDeclaration();
139 } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
140 while (VD) {
141 ASTLocation(VD).print(OS);
142 VD = VD->getPreviousDeclaration();
144 } else
145 ASTLocation(D).print(OS);
146 break;
151 static void ProcessNode(ASTLocation Node, IndexProvider &IdxProvider) {
152 assert(Node.isValid());
154 Decl *D = 0;
155 if (Node.hasStmt()) {
156 if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(Node.getStmt()))
157 D = RefExpr->getDecl();
158 } else {
159 D = Node.getDecl();
161 assert(D);
163 Entity *Ent = Entity::get(D, IdxProvider.getProgram());
164 // If there is no Entity associated with this Decl, it means that it's not
165 // visible to other translation units.
166 if (!Ent)
167 return ProcessDecl(D);
169 // Find the "same" Decl in other translation units and print information.
170 for (IndexProvider::translation_unit_iterator
171 I = IdxProvider.translation_units_begin(Ent),
172 E = IdxProvider.translation_units_end(Ent); I != E; ++I) {
173 TUnit *TU = static_cast<TUnit*>(*I);
174 Decl *OtherD = Ent->getDecl(TU->getASTContext());
175 assert(OtherD && "Couldn't resolve Entity");
176 ProcessDecl(OtherD);
180 static llvm::cl::list<std::string>
181 InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
183 int main(int argc, char **argv) {
184 llvm::sys::PrintStackTraceOnErrorSignal();
185 llvm::PrettyStackTraceProgram X(argc, argv);
186 llvm::cl::ParseCommandLineOptions(argc, argv,
187 "LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
189 FileManager FileMgr;
191 Program Prog;
192 IndexProvider IdxProvider(Prog);
193 llvm::SmallVector<TUnit*, 4> TUnits;
195 // If no input was specified, read from stdin.
196 if (InputFilenames.empty())
197 InputFilenames.push_back("-");
199 for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
200 const std::string &InFile = InputFilenames[i];
202 std::string ErrMsg;
203 llvm::OwningPtr<ASTUnit> AST;
205 AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
206 if (!AST) {
207 llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
208 return 1;
211 TUnit *TU = new TUnit(AST.take(), InFile);
212 TUnits.push_back(TU);
214 IdxProvider.IndexAST(TU);
217 ASTLocation Node;
218 const std::string &FirstFile = TUnits[0]->Filename;
219 ASTUnit *FirstAST = TUnits[0]->AST.get();
221 if (!PointAtLocation.empty()) {
222 const std::string &Filename = PointAtLocation[0].FileName;
223 const FileEntry *File = FileMgr.getFile(Filename);
225 // Safety check. Using an out-of-date AST file will only lead to crashes
226 // or incorrect results.
227 // FIXME: Check all the source files that make up the AST file.
228 const FileEntry *ASTFile = FileMgr.getFile(FirstFile);
229 if (File->getModificationTime() > ASTFile->getModificationTime()) {
230 llvm::errs() << "[" << FirstFile << "] Error: " <<
231 "Pointing at a source file which was modified after creating "
232 "the AST file\n";
233 return 1;
236 if (File == 0) {
237 llvm::errs() << "File '" << Filename << "' does not exist\n";
238 return 1;
240 unsigned Line = PointAtLocation[0].Line;
241 unsigned Col = PointAtLocation[0].Column;
243 SourceLocation Loc =
244 FirstAST->getSourceManager().getLocation(File, Line, Col);
245 if (Loc.isInvalid()) {
246 llvm::errs() << "[" << FirstFile << "] Error: " <<
247 "Couldn't resolve source location (invalid location)\n";
248 return 1;
251 Node = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
252 if (Node.isInvalid()) {
253 llvm::errs() << "[" << FirstFile << "] Error: " <<
254 "Couldn't resolve source location (no declaration found)\n";
255 return 1;
259 if (Node.isValid()) {
260 if (ProgAction == PrintPoint) {
261 llvm::raw_ostream &OS = llvm::outs();
262 Node.print(OS);
263 if (const char *Comment =
264 FirstAST->getASTContext().getCommentForDecl(Node.getDecl()))
265 OS << "Comment associated with this declaration:\n" << Comment << "\n";
266 } else {
267 ProcessNode(Node, IdxProvider);
271 if (!DisableFree) {
272 for (int i=0, e=TUnits.size(); i != e; ++i)
273 delete TUnits[i];
276 // Managed static deconstruction. Useful for making things like
277 // -time-passes usable.
278 llvm::llvm_shutdown();
280 return 0;