blob: 72781c324c7866003aa85ac030533c9f4bed1dd4 [file] [log] [blame]
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +00001//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===//
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 defines the ResolveLocationInAST function, which resolves a
Argiris Kirtzidis98eec712009-07-06 21:35:02 +000011// source location into a ASTLocation.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000012//
13//===----------------------------------------------------------------------===//
14
Argiris Kirtzidis98eec712009-07-06 21:35:02 +000015#include "clang/Index/Utils.h"
Argiris Kirtzidis75abd9c2009-07-06 21:34:47 +000016#include "clang/Index/ASTLocation.h"
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000017#include "clang/AST/DeclVisitor.h"
18#include "clang/AST/StmtVisitor.h"
19#include "clang/Lex/Lexer.h"
20#include "clang/Basic/SourceManager.h"
21#include "llvm/Support/Compiler.h"
22using namespace clang;
Argiris Kirtzidis75abd9c2009-07-06 21:34:47 +000023using namespace idx;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000024
25namespace {
26
27/// \brief Base for the LocResolver classes. Mostly does source range checking.
28class VISIBILITY_HIDDEN LocResolverBase {
29protected:
30 ASTContext &Ctx;
31 SourceLocation Loc;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000032
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000033 enum RangePos {
34 BeforeLoc,
35 ContainsLoc,
36 AfterLoc
37 };
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000038
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000039 RangePos CheckRange(SourceRange Range);
40 RangePos CheckRange(Decl *D) { return CheckRange(D->getSourceRange()); }
41 RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); }
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000042
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +000043 template <typename T>
44 bool isBeforeLocation(T *Node) {
45 return CheckRange(Node) == BeforeLoc;
46 }
47
48 template <typename T>
49 bool ContainsLocation(T *Node) {
50 return CheckRange(Node) == ContainsLoc;
51 }
52
53 template <typename T>
54 bool isAfterLocation(T *Node) {
55 return CheckRange(Node) == AfterLoc;
56 }
57
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000058public:
59 LocResolverBase(ASTContext &ctx, SourceLocation loc)
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000060 : Ctx(ctx), Loc(loc) {}
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000061
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +000062#ifndef NDEBUG
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000063 /// \brief Debugging output.
64 void print(Decl *D);
65 /// \brief Debugging output.
66 void print(Stmt *Node);
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +000067#endif
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000068};
69
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000070/// \brief Searches a statement for the ASTLocation that corresponds to a source
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000071/// location.
72class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000073 public StmtVisitor<StmtLocResolver,
74 ASTLocation > {
Argiris Kirtzidis668516f2009-07-18 00:33:52 +000075 Decl * const Parent;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000076
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000077public:
78 StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
79 : LocResolverBase(ctx, loc), Parent(parent) {}
80
81 ASTLocation VisitDeclStmt(DeclStmt *Node);
Argiris Kirtzidis668516f2009-07-18 00:33:52 +000082 ASTLocation VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000083 ASTLocation VisitStmt(Stmt *Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000084};
85
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000086/// \brief Searches a declaration for the ASTLocation that corresponds to a
87/// source location.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000088class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000089 public DeclVisitor<DeclLocResolver,
90 ASTLocation > {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000091public:
92 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
93 : LocResolverBase(ctx, loc) {}
94
Argiris Kirtzidis875544f2009-07-14 03:18:17 +000095 ASTLocation VisitDeclContext(DeclContext *DC);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000096 ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
97 ASTLocation VisitVarDecl(VarDecl *D);
98 ASTLocation VisitFunctionDecl(FunctionDecl *D);
Argiris Kirtzidis668516f2009-07-18 00:33:52 +000099 ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000100 ASTLocation VisitDecl(Decl *D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000101};
102
103} // anonymous namespace
104
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000105ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000106 assert(ContainsLocation(Node) &&
107 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000108
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000109 // Search all declarations of this DeclStmt.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000110 for (DeclStmt::decl_iterator
111 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000112 RangePos RP = CheckRange(*I);
113 if (RP == AfterLoc)
114 break;
115 if (RP == ContainsLoc)
116 return DeclLocResolver(Ctx, Loc).Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000117 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000118
119 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000120}
121
Argiris Kirtzidis668516f2009-07-18 00:33:52 +0000122ASTLocation StmtLocResolver::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
123 assert(ContainsLocation(Node) &&
124 "Should visit only after verifying that loc is in range");
125 return ASTLocation(Parent, Node);
126}
127
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000128ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000129 assert(ContainsLocation(Node) &&
130 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000131
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000132 // Search the child statements.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000133 for (Stmt::child_iterator
134 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000135 RangePos RP = CheckRange(*I);
136 if (RP == AfterLoc)
137 break;
138 if (RP == ContainsLoc)
139 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000140 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000141
142 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000143}
144
Argiris Kirtzidis875544f2009-07-14 03:18:17 +0000145ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000146 for (DeclContext::decl_iterator
Argiris Kirtzidisab6e38a2009-06-30 02:36:12 +0000147 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000148 RangePos RP = CheckRange(*I);
149 if (RP == AfterLoc)
150 break;
151 if (RP == ContainsLoc)
152 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000153 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000154
Argiris Kirtzidis875544f2009-07-14 03:18:17 +0000155 return ASTLocation(cast<Decl>(DC));
156}
157
158ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
159 ASTLocation ASTLoc = VisitDeclContext(TU);
160 if (ASTLoc.getDecl() == TU)
161 return ASTLocation();
162 return ASTLoc;
163}
164
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000165ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000166 assert(ContainsLocation(D) &&
167 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000168
169 // First, search through the parameters of the function.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000170 for (FunctionDecl::param_iterator
171 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000172 RangePos RP = CheckRange(*I);
173 if (RP == AfterLoc)
174 return ASTLocation(D);
175 if (RP == ContainsLoc)
176 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000177 }
178
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000179 // We didn't find the location in the parameters and we didn't get passed it.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000180
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000181 if (!D->isThisDeclarationADefinition())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000182 return ASTLocation(D);
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000183
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000184 // Second, search through the declarations that are part of the function.
185 // If we find he location there, we won't have to search through its body.
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000186
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000187 for (DeclContext::decl_iterator
188 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
189 if (isa<ParmVarDecl>(*I))
190 continue; // We already searched through the parameters.
191
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000192 RangePos RP = CheckRange(*I);
193 if (RP == AfterLoc)
194 break;
195 if (RP == ContainsLoc)
196 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000197 }
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000198
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000199 // We didn't find a declaration that corresponds to the source location.
200
201 // Finally, search through the body of the function.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000202 Stmt *Body = D->getBody();
203 assert(Body && "Expected definition");
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000204 assert(!isBeforeLocation(Body) &&
205 "This function is supposed to contain the loc");
206 if (isAfterLocation(Body))
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000207 return ASTLocation(D);
208
209 // The body contains the location.
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000210 assert(ContainsLocation(Body));
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000211 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000212}
213
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000214ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000215 assert(ContainsLocation(D) &&
216 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000217
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000218 // Check whether the location points to the init expression.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000219 Expr *Init = D->getInit();
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000220 if (Init && ContainsLocation(Init))
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000221 return StmtLocResolver(Ctx, Loc, D).Visit(Init);
222
223 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000224}
225
Argiris Kirtzidis668516f2009-07-18 00:33:52 +0000226ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) {
227 assert(ContainsLocation(D) &&
228 "Should visit only after verifying that loc is in range");
229
230 // First, search through the parameters of the method.
231 for (ObjCMethodDecl::param_iterator
232 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
233 RangePos RP = CheckRange(*I);
234 if (RP == AfterLoc)
235 return ASTLocation(D);
236 if (RP == ContainsLoc)
237 return Visit(*I);
238 }
239
240 // We didn't find the location in the parameters and we didn't get passed it.
241
242 if (!D->getBody())
243 return ASTLocation(D);
244
245 // Second, search through the declarations that are part of the method.
246 // If we find he location there, we won't have to search through its body.
247
248 for (DeclContext::decl_iterator
249 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
250 if (isa<ParmVarDecl>(*I))
251 continue; // We already searched through the parameters.
252
253 RangePos RP = CheckRange(*I);
254 if (RP == AfterLoc)
255 break;
256 if (RP == ContainsLoc)
257 return Visit(*I);
258 }
259
260 // We didn't find a declaration that corresponds to the source location.
261
262 // Finally, search through the body of the method.
263 Stmt *Body = D->getBody();
264 assert(Body && "Expected definition");
265 assert(!isBeforeLocation(Body) &&
266 "This method is supposed to contain the loc");
267 if (isAfterLocation(Body))
268 return ASTLocation(D);
269
270 // The body contains the location.
271 assert(ContainsLocation(Body));
272 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
273}
274
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000275ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000276 assert(ContainsLocation(D) &&
277 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis62ee8c62009-07-18 00:33:40 +0000278 if (DeclContext *DC = dyn_cast<DeclContext>(D))
279 return VisitDeclContext(DC);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000280 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000281}
282
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000283LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000284 if (!Range.isValid())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000285 return BeforeLoc; // Keep looking.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000286
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000287 // Update the end source range to cover the full length of the token
288 // positioned at the end of the source range.
289 //
290 // e.g.,
291 // int foo
292 // ^ ^
293 //
294 // will be updated to
295 // int foo
296 // ^ ^
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000297 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
298 Ctx.getSourceManager(),
299 Ctx.getLangOptions());
300 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000301
302 SourceManager &SourceMgr = Ctx.getSourceManager();
303 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
304 return BeforeLoc;
305
306 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
307 return AfterLoc;
308
309 return ContainsLoc;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000310}
311
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +0000312#ifndef NDEBUG
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000313void LocResolverBase::print(Decl *D) {
314 llvm::raw_ostream &OS = llvm::outs();
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +0000315 OS << "#### DECL " << D->getDeclKindName() << " ####\n";
Argiris Kirtzidis9a6fb962009-06-30 02:35:04 +0000316 D->print(OS);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000317 OS << " <";
318 D->getLocStart().print(OS, Ctx.getSourceManager());
319 OS << " > - <";
320 D->getLocEnd().print(OS, Ctx.getSourceManager());
321 OS << ">\n\n";
322 OS.flush();
323}
324
325void LocResolverBase::print(Stmt *Node) {
326 llvm::raw_ostream &OS = llvm::outs();
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +0000327 OS << "#### STMT " << Node->getStmtClassName() << " ####\n";
Chris Lattner7099c782009-06-30 01:26:17 +0000328 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000329 OS << " <";
330 Node->getLocStart().print(OS, Ctx.getSourceManager());
331 OS << " > - <";
332 Node->getLocEnd().print(OS, Ctx.getSourceManager());
333 OS << ">\n\n";
334 OS.flush();
335}
Argiris Kirtzidise05ecfb2009-07-17 01:20:03 +0000336#endif
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000337
338
339/// \brief Returns the AST node that a source location points to.
340///
Argiris Kirtzidis98eec712009-07-06 21:35:02 +0000341ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000342 if (Loc.isInvalid())
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +0000343 return ASTLocation();
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000344
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000345 return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000346}