blob: 3908e894663dcb8dc3f7c257ffd38822ba354882 [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
166 I = DC->decls_begin(Ctx), E = DC->decls_end(Ctx); I != E; ++I) {
167 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
200 // Second, search through the declarations that are part of the function.
201 // If we find he location there, we won't have to search through its body.
202 DeclLocResolver DLR(Ctx, Loc);
203 DLR.VisitDeclContext(D);
204 if (DLR.FoundIt()) {
205 llvm::tie(Dcl, Stm) = DLR.getResult();
206 return;
207 }
208
209 // We didn't find a declaration that corresponds to the source location.
210
211 // Finally, search through the body of the function.
212 if (D->isThisDeclarationADefinition()) {
213 StmtLocResolver SLR(Ctx, Loc);
Argyrios Kyrtzidis6fb0aee2009-06-30 02:35:26 +0000214 SLR.Visit(D->getBody());
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000215 if (SLR.FoundIt()) {
216 llvm::tie(Dcl, Stm) = SLR.getResult();
217 // If we didn't find a more immediate 'parent' declaration for the
218 // statement, set the function as the parent.
219 if (Dcl == 0)
220 Dcl = D;
221 }
222 }
223}
224
225void DeclLocResolver::VisitVarDecl(VarDecl *D) {
226 CheckRange(D);
227 if (!FoundIt())
228 return;
229 assert(Dcl == D && "Result not updated ?");
230
231 // Check whether the location points to the init expression.
232 if (D->getInit()) {
233 StmtLocResolver SLR(Ctx, Loc);
234 SLR.Visit(D->getInit());
235 Stm = SLR.getStmt();
236 }
237}
238
239void DeclLocResolver::VisitDecl(Decl *D) {
240 CheckRange(D);
241}
242
243void LocResolverBase::CheckRange(Decl *D) {
244 SourceRange Range = D->getSourceRange();
245 if (!Range.isValid())
246 return;
247
248 FixRange(Range);
249
250 SourceManager &SourceMgr = Ctx.getSourceManager();
251 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
252 return;
253
254 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
255 PassedLoc = true;
256 else
257 Dcl = D;
258}
259
260void LocResolverBase::CheckRange(Stmt *Node) {
261 SourceRange Range = Node->getSourceRange();
262 if (!Range.isValid())
263 return;
264
265 FixRange(Range);
266
267 SourceManager &SourceMgr = Ctx.getSourceManager();
268 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
269 return;
270
271 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
272 PassedLoc = true;
273 else
274 Stm = Node;
275}
276
277void LocResolverBase::FixRange(SourceRange &Range) {
278 if (!Range.isValid())
279 return;
280
281 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
282 Ctx.getSourceManager(),
283 Ctx.getLangOptions());
284 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
285}
286
287void LocResolverBase::print(Decl *D) {
288 llvm::raw_ostream &OS = llvm::outs();
289 OS << "#### DECL ####\n";
Argyrios Kyrtzidisf1d60ea2009-06-30 02:35:04 +0000290 D->print(OS);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000291 OS << " <";
292 D->getLocStart().print(OS, Ctx.getSourceManager());
293 OS << " > - <";
294 D->getLocEnd().print(OS, Ctx.getSourceManager());
295 OS << ">\n\n";
296 OS.flush();
297}
298
299void LocResolverBase::print(Stmt *Node) {
300 llvm::raw_ostream &OS = llvm::outs();
301 OS << "#### STMT ####\n";
Chris Lattnere4f21422009-06-30 01:26:17 +0000302 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000303 OS << " <";
304 Node->getLocStart().print(OS, Ctx.getSourceManager());
305 OS << " > - <";
306 Node->getLocEnd().print(OS, Ctx.getSourceManager());
307 OS << ">\n\n";
308 OS.flush();
309}
310
311
312/// \brief Returns the AST node that a source location points to.
313///
314std::pair<Decl *, Stmt *>
315clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
316 if (Loc.isInvalid())
317 return std::make_pair((Decl*)0, (Stmt*)0);
318
319 DeclLocResolver DLR(Ctx, Loc);
320 DLR.Visit(Ctx.getTranslationUnitDecl());
321 return DLR.getResult();
322}