blob: edb46c23f4f3162a2fba5ce8774a59a8bddf861b [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 Kirtzidis40bf2832009-06-25 18:22:41 +000062 /// \brief Debugging output.
63 void print(Decl *D);
64 /// \brief Debugging output.
65 void print(Stmt *Node);
66};
67
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000068/// \brief Searches a statement for the ASTLocation that corresponds to a source
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000069/// location.
70class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000071 public StmtVisitor<StmtLocResolver,
72 ASTLocation > {
73 Decl *Parent;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000074
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000075public:
76 StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
77 : LocResolverBase(ctx, loc), Parent(parent) {}
78
79 ASTLocation VisitDeclStmt(DeclStmt *Node);
80 ASTLocation VisitStmt(Stmt *Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000081};
82
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000083/// \brief Searches a declaration for the ASTLocation that corresponds to a
84/// source location.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000085class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000086 public DeclVisitor<DeclLocResolver,
87 ASTLocation > {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000088public:
89 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
90 : LocResolverBase(ctx, loc) {}
91
Argiris Kirtzidis875544f2009-07-14 03:18:17 +000092 ASTLocation VisitDeclContext(DeclContext *DC);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000093 ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
Argiris Kirtzidis875544f2009-07-14 03:18:17 +000094 ASTLocation VisitRecordDecl(RecordDecl *D);
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000095 ASTLocation VisitVarDecl(VarDecl *D);
96 ASTLocation VisitFunctionDecl(FunctionDecl *D);
97 ASTLocation VisitDecl(Decl *D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000098};
99
100} // anonymous namespace
101
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000102ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000103 assert(ContainsLocation(Node) &&
104 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000105
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000106 // Search all declarations of this DeclStmt.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000107 for (DeclStmt::decl_iterator
108 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000109 RangePos RP = CheckRange(*I);
110 if (RP == AfterLoc)
111 break;
112 if (RP == ContainsLoc)
113 return DeclLocResolver(Ctx, Loc).Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000114 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000115
116 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000117}
118
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000119ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000120 assert(ContainsLocation(Node) &&
121 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000122
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000123 // Search the child statements.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000124 for (Stmt::child_iterator
125 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000126 RangePos RP = CheckRange(*I);
127 if (RP == AfterLoc)
128 break;
129 if (RP == ContainsLoc)
130 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000131 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000132
133 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000134}
135
Argiris Kirtzidis875544f2009-07-14 03:18:17 +0000136ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000137 for (DeclContext::decl_iterator
Argiris Kirtzidisab6e38a2009-06-30 02:36:12 +0000138 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000139 RangePos RP = CheckRange(*I);
140 if (RP == AfterLoc)
141 break;
142 if (RP == ContainsLoc)
143 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000144 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000145
Argiris Kirtzidis875544f2009-07-14 03:18:17 +0000146 return ASTLocation(cast<Decl>(DC));
147}
148
149ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
150 ASTLocation ASTLoc = VisitDeclContext(TU);
151 if (ASTLoc.getDecl() == TU)
152 return ASTLocation();
153 return ASTLoc;
154}
155
156ASTLocation DeclLocResolver::VisitRecordDecl(RecordDecl *D) {
157 assert(ContainsLocation(D) &&
158 "Should visit only after verifying that loc is in range");
159 return VisitDeclContext(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000160}
161
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000162ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000163 assert(ContainsLocation(D) &&
164 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000165
166 // First, search through the parameters of the function.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000167 for (FunctionDecl::param_iterator
168 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000169 RangePos RP = CheckRange(*I);
170 if (RP == AfterLoc)
171 return ASTLocation(D);
172 if (RP == ContainsLoc)
173 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000174 }
175
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000176 // We didn't find the location in the parameters and we didn't get passed it.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000177
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000178 if (!D->isThisDeclarationADefinition())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000179 return ASTLocation(D);
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000180
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000181 // Second, search through the declarations that are part of the function.
182 // If we find he location there, we won't have to search through its body.
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000183
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000184 for (DeclContext::decl_iterator
185 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
186 if (isa<ParmVarDecl>(*I))
187 continue; // We already searched through the parameters.
188
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000189 RangePos RP = CheckRange(*I);
190 if (RP == AfterLoc)
191 break;
192 if (RP == ContainsLoc)
193 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000194 }
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000195
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000196 // We didn't find a declaration that corresponds to the source location.
197
198 // Finally, search through the body of the function.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000199 Stmt *Body = D->getBody();
200 assert(Body && "Expected definition");
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000201 assert(!isBeforeLocation(Body) &&
202 "This function is supposed to contain the loc");
203 if (isAfterLocation(Body))
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000204 return ASTLocation(D);
205
206 // The body contains the location.
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000207 assert(ContainsLocation(Body));
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000208 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000209}
210
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000211ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000212 assert(ContainsLocation(D) &&
213 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000214
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000215 // Check whether the location points to the init expression.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000216 Expr *Init = D->getInit();
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000217 if (Init && ContainsLocation(Init))
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000218 return StmtLocResolver(Ctx, Loc, D).Visit(Init);
219
220 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000221}
222
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000223ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
Argiris Kirtzidis8be9dda2009-07-10 03:41:26 +0000224 assert(ContainsLocation(D) &&
225 "Should visit only after verifying that loc is in range");
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000226 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000227}
228
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000229LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000230 if (!Range.isValid())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000231 return BeforeLoc; // Keep looking.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000232
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000233 // Update the end source range to cover the full length of the token
234 // positioned at the end of the source range.
235 //
236 // e.g.,
237 // int foo
238 // ^ ^
239 //
240 // will be updated to
241 // int foo
242 // ^ ^
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000243 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
244 Ctx.getSourceManager(),
245 Ctx.getLangOptions());
246 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000247
248 SourceManager &SourceMgr = Ctx.getSourceManager();
249 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
250 return BeforeLoc;
251
252 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
253 return AfterLoc;
254
255 return ContainsLoc;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000256}
257
258void LocResolverBase::print(Decl *D) {
259 llvm::raw_ostream &OS = llvm::outs();
260 OS << "#### DECL ####\n";
Argiris Kirtzidis9a6fb962009-06-30 02:35:04 +0000261 D->print(OS);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000262 OS << " <";
263 D->getLocStart().print(OS, Ctx.getSourceManager());
264 OS << " > - <";
265 D->getLocEnd().print(OS, Ctx.getSourceManager());
266 OS << ">\n\n";
267 OS.flush();
268}
269
270void LocResolverBase::print(Stmt *Node) {
271 llvm::raw_ostream &OS = llvm::outs();
272 OS << "#### STMT ####\n";
Chris Lattner7099c782009-06-30 01:26:17 +0000273 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000274 OS << " <";
275 Node->getLocStart().print(OS, Ctx.getSourceManager());
276 OS << " > - <";
277 Node->getLocEnd().print(OS, Ctx.getSourceManager());
278 OS << ">\n\n";
279 OS.flush();
280}
281
282
283/// \brief Returns the AST node that a source location points to.
284///
Argiris Kirtzidis98eec712009-07-06 21:35:02 +0000285ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000286 if (Loc.isInvalid())
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +0000287 return ASTLocation();
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000288
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000289 return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000290}