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