blob: 281f4d9df12b8305a4f65a35d4a281d3bf14f49d [file] [log] [blame]
Argyrios Kyrtzidis53d4c142009-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
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000011// source location into a ASTLocation.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000012//
13//===----------------------------------------------------------------------===//
14
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000015#include "clang/Index/Utils.h"
Argyrios Kyrtzidisccbcb702009-07-06 21:34:47 +000016#include "clang/Index/ASTLocation.h"
Argyrios Kyrtzidis53d4c142009-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;
Argyrios Kyrtzidisccbcb702009-07-06 21:34:47 +000023using namespace idx;
Argyrios Kyrtzidis53d4c142009-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;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000032
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000033 enum RangePos {
34 BeforeLoc,
35 ContainsLoc,
36 AfterLoc
37 };
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000038
Argyrios Kyrtzidisbd2ab6e2009-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()); }
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000042
Argyrios Kyrtzidisa6488a12009-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
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000058public:
59 LocResolverBase(ASTContext &ctx, SourceLocation loc)
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000060 : Ctx(ctx), Loc(loc) {}
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000061
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +000062#ifndef NDEBUG
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000063 /// \brief Debugging output.
64 void print(Decl *D);
65 /// \brief Debugging output.
66 void print(Stmt *Node);
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +000067#endif
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000068};
69
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000070/// \brief Searches a statement for the ASTLocation that corresponds to a source
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000071/// location.
72class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000073 public StmtVisitor<StmtLocResolver,
74 ASTLocation > {
Argyrios Kyrtzidis0df13472009-07-18 00:33:52 +000075 Decl * const Parent;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000076
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000077public:
78 StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
79 : LocResolverBase(ctx, loc), Parent(parent) {}
80
Argyrios Kyrtzidis8c4dc1f2009-07-31 19:02:11 +000081 ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node);
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000082 ASTLocation VisitDeclStmt(DeclStmt *Node);
83 ASTLocation VisitStmt(Stmt *Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000084};
85
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000086/// \brief Searches a declaration for the ASTLocation that corresponds to a
87/// source location.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000088class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000089 public DeclVisitor<DeclLocResolver,
90 ASTLocation > {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000091public:
92 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
93 : LocResolverBase(ctx, loc) {}
94
Argyrios Kyrtzidis2e46aee2009-07-14 03:18:17 +000095 ASTLocation VisitDeclContext(DeclContext *DC);
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000096 ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
97 ASTLocation VisitVarDecl(VarDecl *D);
98 ASTLocation VisitFunctionDecl(FunctionDecl *D);
Argyrios Kyrtzidis0df13472009-07-18 00:33:52 +000099 ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D);
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000100 ASTLocation VisitDecl(Decl *D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000101};
102
103} // anonymous namespace
104
Argyrios Kyrtzidis8c4dc1f2009-07-31 19:02:11 +0000105ASTLocation
106StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
107 assert(ContainsLocation(Node) &&
108 "Should visit only after verifying that loc is in range");
109
110 if (Node->getNumArgs() == 1)
111 // Unary operator. Let normal child traversal handle it.
112 return VisitCallExpr(Node);
113
114 assert(Node->getNumArgs() == 2 &&
115 "Wrong args for the C++ operator call expr ?");
116
117 llvm::SmallVector<Expr *, 3> Nodes;
118 // Binary operator. Check in order of 1-left arg, 2-callee, 3-right arg.
119 Nodes.push_back(Node->getArg(0));
120 Nodes.push_back(Node->getCallee());
121 Nodes.push_back(Node->getArg(1));
Mike Stump1eb44332009-09-09 15:08:12 +0000122
Argyrios Kyrtzidis8c4dc1f2009-07-31 19:02:11 +0000123 for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
124 RangePos RP = CheckRange(Nodes[i]);
125 if (RP == AfterLoc)
126 break;
127 if (RP == ContainsLoc)
128 return Visit(Nodes[i]);
129 }
130
131 return ASTLocation(Parent, Node);
132}
133
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000134ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000135 assert(ContainsLocation(Node) &&
136 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000137
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000138 // Search all declarations of this DeclStmt.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000139 for (DeclStmt::decl_iterator
140 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000141 RangePos RP = CheckRange(*I);
142 if (RP == AfterLoc)
143 break;
144 if (RP == ContainsLoc)
145 return DeclLocResolver(Ctx, Loc).Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000146 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000147
148 return ASTLocation(Parent, Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000149}
150
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000151ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000152 assert(ContainsLocation(Node) &&
153 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000154
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000155 // Search the child statements.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000156 for (Stmt::child_iterator
157 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Argyrios Kyrtzidis8c4dc1f2009-07-31 19:02:11 +0000158 if (*I == NULL)
159 continue;
160
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000161 RangePos RP = CheckRange(*I);
162 if (RP == AfterLoc)
163 break;
164 if (RP == ContainsLoc)
165 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000166 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000167
168 return ASTLocation(Parent, Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000169}
170
Argyrios Kyrtzidis2e46aee2009-07-14 03:18:17 +0000171ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000172 for (DeclContext::decl_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000173 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000174 RangePos RP = CheckRange(*I);
175 if (RP == AfterLoc)
176 break;
177 if (RP == ContainsLoc)
178 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000179 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000180
Argyrios Kyrtzidis2e46aee2009-07-14 03:18:17 +0000181 return ASTLocation(cast<Decl>(DC));
182}
183
184ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
185 ASTLocation ASTLoc = VisitDeclContext(TU);
186 if (ASTLoc.getDecl() == TU)
187 return ASTLocation();
188 return ASTLoc;
189}
190
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000191ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000192 assert(ContainsLocation(D) &&
193 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000194
195 // First, search through the parameters of the function.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000196 for (FunctionDecl::param_iterator
197 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000198 RangePos RP = CheckRange(*I);
199 if (RP == AfterLoc)
200 return ASTLocation(D);
201 if (RP == ContainsLoc)
202 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000203 }
Mike Stump1eb44332009-09-09 15:08:12 +0000204
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000205 // We didn't find the location in the parameters and we didn't get passed it.
Mike Stump1eb44332009-09-09 15:08:12 +0000206
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000207 if (!D->isThisDeclarationADefinition())
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000208 return ASTLocation(D);
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000209
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000210 // Second, search through the declarations that are part of the function.
211 // If we find he location there, we won't have to search through its body.
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000212
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000213 for (DeclContext::decl_iterator
214 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
215 if (isa<ParmVarDecl>(*I))
216 continue; // We already searched through the parameters.
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000218 RangePos RP = CheckRange(*I);
219 if (RP == AfterLoc)
220 break;
221 if (RP == ContainsLoc)
222 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000223 }
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000224
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000225 // We didn't find a declaration that corresponds to the source location.
Mike Stump1eb44332009-09-09 15:08:12 +0000226
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000227 // Finally, search through the body of the function.
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000228 Stmt *Body = D->getBody();
229 assert(Body && "Expected definition");
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000230 assert(!isBeforeLocation(Body) &&
231 "This function is supposed to contain the loc");
232 if (isAfterLocation(Body))
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000233 return ASTLocation(D);
234
235 // The body contains the location.
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000236 assert(ContainsLocation(Body));
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000237 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000238}
239
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000240ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000241 assert(ContainsLocation(D) &&
242 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000243
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000244 // Check whether the location points to the init expression.
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000245 Expr *Init = D->getInit();
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000246 if (Init && ContainsLocation(Init))
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000247 return StmtLocResolver(Ctx, Loc, D).Visit(Init);
248
249 return ASTLocation(D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000250}
251
Argyrios Kyrtzidis0df13472009-07-18 00:33:52 +0000252ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) {
253 assert(ContainsLocation(D) &&
254 "Should visit only after verifying that loc is in range");
255
256 // First, search through the parameters of the method.
257 for (ObjCMethodDecl::param_iterator
258 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
259 RangePos RP = CheckRange(*I);
260 if (RP == AfterLoc)
261 return ASTLocation(D);
262 if (RP == ContainsLoc)
263 return Visit(*I);
264 }
265
266 // We didn't find the location in the parameters and we didn't get passed it.
267
268 if (!D->getBody())
269 return ASTLocation(D);
270
271 // Second, search through the declarations that are part of the method.
272 // If we find he location there, we won't have to search through its body.
273
274 for (DeclContext::decl_iterator
275 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
276 if (isa<ParmVarDecl>(*I))
277 continue; // We already searched through the parameters.
278
279 RangePos RP = CheckRange(*I);
280 if (RP == AfterLoc)
281 break;
282 if (RP == ContainsLoc)
283 return Visit(*I);
284 }
285
286 // We didn't find a declaration that corresponds to the source location.
287
288 // Finally, search through the body of the method.
289 Stmt *Body = D->getBody();
290 assert(Body && "Expected definition");
291 assert(!isBeforeLocation(Body) &&
292 "This method is supposed to contain the loc");
293 if (isAfterLocation(Body))
294 return ASTLocation(D);
295
296 // The body contains the location.
297 assert(ContainsLocation(Body));
298 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
299}
300
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000301ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000302 assert(ContainsLocation(D) &&
303 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidis7e4fe3b2009-07-18 00:33:40 +0000304 if (DeclContext *DC = dyn_cast<DeclContext>(D))
305 return VisitDeclContext(DC);
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000306 return ASTLocation(D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000307}
308
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000309LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000310 if (!Range.isValid())
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000311 return BeforeLoc; // Keep looking.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000312
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000313 // Update the end source range to cover the full length of the token
314 // positioned at the end of the source range.
315 //
316 // e.g.,
317 // int foo
318 // ^ ^
319 //
320 // will be updated to
321 // int foo
322 // ^ ^
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000323 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
324 Ctx.getSourceManager(),
325 Ctx.getLangOptions());
326 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000327
Mike Stump1eb44332009-09-09 15:08:12 +0000328 SourceManager &SourceMgr = Ctx.getSourceManager();
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000329 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
330 return BeforeLoc;
Mike Stump1eb44332009-09-09 15:08:12 +0000331
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000332 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
333 return AfterLoc;
334
335 return ContainsLoc;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000336}
337
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +0000338#ifndef NDEBUG
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000339void LocResolverBase::print(Decl *D) {
340 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +0000341 OS << "#### DECL " << D->getDeclKindName() << " ####\n";
Argyrios Kyrtzidisf1d60ea2009-06-30 02:35:04 +0000342 D->print(OS);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000343 OS << " <";
344 D->getLocStart().print(OS, Ctx.getSourceManager());
345 OS << " > - <";
346 D->getLocEnd().print(OS, Ctx.getSourceManager());
347 OS << ">\n\n";
348 OS.flush();
349}
350
351void LocResolverBase::print(Stmt *Node) {
352 llvm::raw_ostream &OS = llvm::outs();
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +0000353 OS << "#### STMT " << Node->getStmtClassName() << " ####\n";
Chris Lattnere4f21422009-06-30 01:26:17 +0000354 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000355 OS << " <";
356 Node->getLocStart().print(OS, Ctx.getSourceManager());
357 OS << " > - <";
358 Node->getLocEnd().print(OS, Ctx.getSourceManager());
359 OS << ">\n\n";
360 OS.flush();
361}
Argyrios Kyrtzidisada45422009-07-17 01:20:03 +0000362#endif
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000363
364
365/// \brief Returns the AST node that a source location points to.
366///
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +0000367ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000368 if (Loc.isInvalid())
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000369 return ASTLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000370
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000371 return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000372}