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