blob: 5b8eed0c0ef833a9747952c9cd765bf740473c65 [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
11// source location into a <Decl *, Stmt *> pair.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Frontend/Utils.h"
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +000016#include "clang/AST/ASTNode.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;
23
24namespace {
25
26/// \brief Base for the LocResolver classes. Mostly does source range checking.
27class VISIBILITY_HIDDEN LocResolverBase {
28protected:
29 ASTContext &Ctx;
30 SourceLocation Loc;
31
32 Decl *Dcl;
33 Stmt *Stm;
34 bool PassedLoc;
35
36 /// \brief Checks whether Loc is in the source range of 'D'.
37 ///
38 /// If it is, updates Dcl. If Loc is passed the source range, it sets
39 /// PassedLoc, otherwise it does nothing.
40 void CheckRange(Decl *D);
41
42 /// \brief Checks whether Loc is in the source range of 'Node'.
43 ///
44 /// If it is, updates Stm. If Loc is passed the source range, it sets
45 /// PassedLoc, otherwise it does nothing.
46 void CheckRange(Stmt *Node);
47
48 /// \brief Updates the end source range to cover the full length of the token
49 /// positioned at the end of the source range.
50 ///
51 /// e.g.,
52 /// @code
53 /// int foo
54 /// ^ ^
55 /// @endcode
56 /// will be updated to
57 /// @code
58 /// int foo
59 /// ^ ^
60 /// @endcode
61 void FixRange(SourceRange &Range);
62
63public:
64 LocResolverBase(ASTContext &ctx, SourceLocation loc)
65 : Ctx(ctx), Loc(loc), Dcl(0), Stm(0), PassedLoc(0) {}
66
67 /// \brief We found a AST node that corresponds to the source location.
68 bool FoundIt() const { return Dcl != 0 || Stm != 0; }
69
70 /// \brief We either found a AST node or we passed the source location while
71 /// searching.
72 bool Finished() const { return FoundIt() || PassedLoc; }
73
74 Decl *getDecl() const { return Dcl; }
75 Stmt *getStmt() const { return Stm; }
76
77 std::pair<Decl *, Stmt *> getResult() const {
78 return std::make_pair(getDecl(), getStmt());
79 }
80
81 /// \brief Debugging output.
82 void print(Decl *D);
83 /// \brief Debugging output.
84 void print(Stmt *Node);
85};
86
87/// \brief Searches a statement for the AST node that corresponds to a source
88/// location.
89class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
90 public StmtVisitor<StmtLocResolver> {
91public:
92 StmtLocResolver(ASTContext &ctx, SourceLocation loc)
93 : LocResolverBase(ctx, loc) {}
94
95 void VisitDeclStmt(DeclStmt *Node);
96 void VisitStmt(Stmt *Node);
97};
98
99/// \brief Searches a declaration for the AST node that corresponds to a source
100/// location.
101class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
102 public DeclVisitor<DeclLocResolver> {
103public:
104 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
105 : LocResolverBase(ctx, loc) {}
106
107 void VisitDeclContext(DeclContext *DC);
108 void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
109 void VisitVarDecl(VarDecl *D);
110 void VisitFunctionDecl(FunctionDecl *D);
111 void VisitDecl(Decl *D);
112};
113
114} // anonymous namespace
115
116void StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
117 CheckRange(Node);
118 if (!FoundIt())
119 return;
120 assert(Stm == Node && "Result not updated ?");
121
122 // Search all declarations of this DeclStmt. If we found the one corresponding
123 // to the source location, update this StmtLocResolver's result.
124 DeclLocResolver DLR(Ctx, Loc);
125 for (DeclStmt::decl_iterator
126 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
127 DLR.Visit(*I);
128 if (DLR.Finished()) {
129 if (DLR.FoundIt())
130 llvm::tie(Dcl, Stm) = DLR.getResult();
131 return;
132 }
133 }
134}
135
136void StmtLocResolver::VisitStmt(Stmt *Node) {
137 CheckRange(Node);
138 if (!FoundIt())
139 return;
140 assert(Stm == Node && "Result not updated ?");
141
142 // Search the child statements.
143 StmtLocResolver SLR(Ctx, Loc);
144 for (Stmt::child_iterator
145 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
146 SLR.Visit(*I);
147 if (!SLR.Finished())
148 continue;
149
150 // We either found it or we passed the source location.
151
152 if (SLR.FoundIt()) {
153 // Only update Dcl if we found another more immediate 'parent' Decl for
154 // the statement.
155 if (SLR.getDecl())
156 Dcl = SLR.getDecl();
157 Stm = SLR.getStmt();
158 }
159
160 return;
161 }
162}
163
164void DeclLocResolver::VisitDeclContext(DeclContext *DC) {
165 DeclLocResolver DLR(Ctx, Loc);
166 for (DeclContext::decl_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000167 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000168 DLR.Visit(*I);
169 if (DLR.Finished()) {
170 if (DLR.FoundIt())
171 llvm::tie(Dcl, Stm) = DLR.getResult();
172 return;
173 }
174 }
175}
176
177void DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
178 VisitDeclContext(TU);
179}
180
181void DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
182 CheckRange(D);
183 if (!FoundIt())
184 return;
185 assert(Dcl == D && "Result not updated ?");
186
187 // First, search through the parameters of the function.
188 DeclLocResolver ParmRes(Ctx, Loc);
189 for (FunctionDecl::param_iterator
190 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
191 ParmRes.Visit(*I);
192 if (ParmRes.Finished()) {
193 if (ParmRes.FoundIt())
194 llvm::tie(Dcl, Stm) = ParmRes.getResult();
195 return;
196 }
197 }
198
199 // We didn't found the location in the parameters and we didn't get passed it.
200
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000201 if (!D->isThisDeclarationADefinition())
202 return;
203
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000204 // Second, search through the declarations that are part of the function.
205 // If we find he location there, we won't have to search through its body.
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000206
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000207 DeclLocResolver DLR(Ctx, Loc);
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000208 for (DeclContext::decl_iterator
209 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
210 if (isa<ParmVarDecl>(*I))
211 continue; // We already searched through the parameters.
212
213 DLR.Visit(*I);
214 if (DLR.FoundIt()) {
215 llvm::tie(Dcl, Stm) = DLR.getResult();
216 return;
217 }
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000218 }
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000219
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000220 // We didn't find a declaration that corresponds to the source location.
221
222 // Finally, search through the body of the function.
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000223 assert(D->getBody() && "Expected definition");
224 StmtLocResolver SLR(Ctx, Loc);
225 SLR.Visit(D->getBody());
226 if (SLR.FoundIt()) {
227 llvm::tie(Dcl, Stm) = SLR.getResult();
228 // If we didn't find a more immediate 'parent' declaration for the
229 // statement, set the function as the parent.
230 if (Dcl == 0)
231 Dcl = D;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000232 }
233}
234
235void DeclLocResolver::VisitVarDecl(VarDecl *D) {
236 CheckRange(D);
237 if (!FoundIt())
238 return;
239 assert(Dcl == D && "Result not updated ?");
240
241 // Check whether the location points to the init expression.
242 if (D->getInit()) {
243 StmtLocResolver SLR(Ctx, Loc);
244 SLR.Visit(D->getInit());
245 Stm = SLR.getStmt();
246 }
247}
248
249void DeclLocResolver::VisitDecl(Decl *D) {
250 CheckRange(D);
251}
252
253void LocResolverBase::CheckRange(Decl *D) {
254 SourceRange Range = D->getSourceRange();
255 if (!Range.isValid())
256 return;
257
258 FixRange(Range);
259
260 SourceManager &SourceMgr = Ctx.getSourceManager();
261 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
262 return;
263
264 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
265 PassedLoc = true;
266 else
267 Dcl = D;
268}
269
270void LocResolverBase::CheckRange(Stmt *Node) {
271 SourceRange Range = Node->getSourceRange();
272 if (!Range.isValid())
273 return;
274
275 FixRange(Range);
276
277 SourceManager &SourceMgr = Ctx.getSourceManager();
278 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
279 return;
280
281 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
282 PassedLoc = true;
283 else
284 Stm = Node;
285}
286
287void LocResolverBase::FixRange(SourceRange &Range) {
288 if (!Range.isValid())
289 return;
290
291 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
292 Ctx.getSourceManager(),
293 Ctx.getLangOptions());
294 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
295}
296
297void LocResolverBase::print(Decl *D) {
298 llvm::raw_ostream &OS = llvm::outs();
299 OS << "#### DECL ####\n";
Argyrios Kyrtzidisf1d60ea2009-06-30 02:35:04 +0000300 D->print(OS);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000301 OS << " <";
302 D->getLocStart().print(OS, Ctx.getSourceManager());
303 OS << " > - <";
304 D->getLocEnd().print(OS, Ctx.getSourceManager());
305 OS << ">\n\n";
306 OS.flush();
307}
308
309void LocResolverBase::print(Stmt *Node) {
310 llvm::raw_ostream &OS = llvm::outs();
311 OS << "#### STMT ####\n";
Chris Lattnere4f21422009-06-30 01:26:17 +0000312 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000313 OS << " <";
314 Node->getLocStart().print(OS, Ctx.getSourceManager());
315 OS << " > - <";
316 Node->getLocEnd().print(OS, Ctx.getSourceManager());
317 OS << ">\n\n";
318 OS.flush();
319}
320
321
322/// \brief Returns the AST node that a source location points to.
323///
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000324ASTNode clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000325 if (Loc.isInvalid())
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000326 return ASTNode();
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000327
328 DeclLocResolver DLR(Ctx, Loc);
329 DLR.Visit(Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000330 return ASTNode(DLR.getDecl(), DLR.getStmt());
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000331}