blob: 3dcd2143cbc97a0e4c809866463ec30c8b5204d5 [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.
206 DeclLocResolver DLR(Ctx, Loc);
207 DLR.VisitDeclContext(D);
208 if (DLR.FoundIt()) {
209 llvm::tie(Dcl, Stm) = DLR.getResult();
210 return;
211 }
212
213 // We didn't find a declaration that corresponds to the source location.
214
215 // Finally, search through the body of the function.
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000216 assert(D->getBody() && "Expected definition");
217 StmtLocResolver SLR(Ctx, Loc);
218 SLR.Visit(D->getBody());
219 if (SLR.FoundIt()) {
220 llvm::tie(Dcl, Stm) = SLR.getResult();
221 // If we didn't find a more immediate 'parent' declaration for the
222 // statement, set the function as the parent.
223 if (Dcl == 0)
224 Dcl = D;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000225 }
226}
227
228void DeclLocResolver::VisitVarDecl(VarDecl *D) {
229 CheckRange(D);
230 if (!FoundIt())
231 return;
232 assert(Dcl == D && "Result not updated ?");
233
234 // Check whether the location points to the init expression.
235 if (D->getInit()) {
236 StmtLocResolver SLR(Ctx, Loc);
237 SLR.Visit(D->getInit());
238 Stm = SLR.getStmt();
239 }
240}
241
242void DeclLocResolver::VisitDecl(Decl *D) {
243 CheckRange(D);
244}
245
246void LocResolverBase::CheckRange(Decl *D) {
247 SourceRange Range = D->getSourceRange();
248 if (!Range.isValid())
249 return;
250
251 FixRange(Range);
252
253 SourceManager &SourceMgr = Ctx.getSourceManager();
254 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
255 return;
256
257 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
258 PassedLoc = true;
259 else
260 Dcl = D;
261}
262
263void LocResolverBase::CheckRange(Stmt *Node) {
264 SourceRange Range = Node->getSourceRange();
265 if (!Range.isValid())
266 return;
267
268 FixRange(Range);
269
270 SourceManager &SourceMgr = Ctx.getSourceManager();
271 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
272 return;
273
274 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
275 PassedLoc = true;
276 else
277 Stm = Node;
278}
279
280void LocResolverBase::FixRange(SourceRange &Range) {
281 if (!Range.isValid())
282 return;
283
284 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
285 Ctx.getSourceManager(),
286 Ctx.getLangOptions());
287 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
288}
289
290void LocResolverBase::print(Decl *D) {
291 llvm::raw_ostream &OS = llvm::outs();
292 OS << "#### DECL ####\n";
Argyrios Kyrtzidisf1d60ea2009-06-30 02:35:04 +0000293 D->print(OS);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000294 OS << " <";
295 D->getLocStart().print(OS, Ctx.getSourceManager());
296 OS << " > - <";
297 D->getLocEnd().print(OS, Ctx.getSourceManager());
298 OS << ">\n\n";
299 OS.flush();
300}
301
302void LocResolverBase::print(Stmt *Node) {
303 llvm::raw_ostream &OS = llvm::outs();
304 OS << "#### STMT ####\n";
Chris Lattnere4f21422009-06-30 01:26:17 +0000305 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000306 OS << " <";
307 Node->getLocStart().print(OS, Ctx.getSourceManager());
308 OS << " > - <";
309 Node->getLocEnd().print(OS, Ctx.getSourceManager());
310 OS << ">\n\n";
311 OS.flush();
312}
313
314
315/// \brief Returns the AST node that a source location points to.
316///
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000317ASTNode clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000318 if (Loc.isInvalid())
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000319 return ASTNode();
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000320
321 DeclLocResolver DLR(Ctx, Loc);
322 DLR.Visit(Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis49dd5852009-07-05 22:21:40 +0000323 return ASTNode(DLR.getDecl(), DLR.getStmt());
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000324}