blob: e27e9bce4fb98ceae607d10d5f0b3d89df75e8a1 [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
Argiris Kirtzidis98eec712009-07-06 21:35:02 +000011// source location into a ASTLocation.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000012//
13//===----------------------------------------------------------------------===//
14
Argiris Kirtzidis98eec712009-07-06 21:35:02 +000015#include "clang/Index/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;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000032
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000033 enum RangePos {
34 BeforeLoc,
35 ContainsLoc,
36 AfterLoc
37 };
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000038
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000039 RangePos CheckRange(SourceRange Range);
40 RangePos CheckRange(Decl *D) { return CheckRange(D->getSourceRange()); }
41 RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); }
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000042
43public:
44 LocResolverBase(ASTContext &ctx, SourceLocation loc)
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000045 : Ctx(ctx), Loc(loc) {}
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000046
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000047 /// \brief Debugging output.
48 void print(Decl *D);
49 /// \brief Debugging output.
50 void print(Stmt *Node);
51};
52
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000053/// \brief Searches a statement for the ASTLocation that corresponds to a source
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000054/// location.
55class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000056 public StmtVisitor<StmtLocResolver,
57 ASTLocation > {
58 Decl *Parent;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000059
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000060public:
61 StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
62 : LocResolverBase(ctx, loc), Parent(parent) {}
63
64 ASTLocation VisitDeclStmt(DeclStmt *Node);
65 ASTLocation VisitStmt(Stmt *Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000066};
67
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000068/// \brief Searches a declaration for the ASTLocation that corresponds to a
69/// source location.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000070class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000071 public DeclVisitor<DeclLocResolver,
72 ASTLocation > {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000073public:
74 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
75 : LocResolverBase(ctx, loc) {}
76
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000077 ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
78 ASTLocation VisitVarDecl(VarDecl *D);
79 ASTLocation VisitFunctionDecl(FunctionDecl *D);
80 ASTLocation VisitDecl(Decl *D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000081};
82
83} // anonymous namespace
84
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000085ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
86 assert(CheckRange(Node) == ContainsLoc
87 && "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000088
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000089 // Search all declarations of this DeclStmt.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000090 for (DeclStmt::decl_iterator
91 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000092 RangePos RP = CheckRange(*I);
93 if (RP == AfterLoc)
94 break;
95 if (RP == ContainsLoc)
96 return DeclLocResolver(Ctx, Loc).Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +000097 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +000098
99 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000100}
101
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000102ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
103 assert(CheckRange(Node) == ContainsLoc
104 && "Should visit only after verifying that loc is in range");
105
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000106 // Search the child statements.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000107 for (Stmt::child_iterator
108 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000109 RangePos RP = CheckRange(*I);
110 if (RP == AfterLoc)
111 break;
112 if (RP == ContainsLoc)
113 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000114 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000115
116 return ASTLocation(Parent, Node);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000117}
118
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000119ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
120 DeclContext *DC = TU;
121
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000122 for (DeclContext::decl_iterator
Argiris Kirtzidisab6e38a2009-06-30 02:36:12 +0000123 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000124 RangePos RP = CheckRange(*I);
125 if (RP == AfterLoc)
126 break;
127 if (RP == ContainsLoc)
128 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000129 }
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000130
131 return ASTLocation();
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000132}
133
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000134ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
135 assert(CheckRange(D) == ContainsLoc
136 && "Should visit only after verifying that loc is in range");
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000137
138 // First, search through the parameters of the function.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000139 for (FunctionDecl::param_iterator
140 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000141 RangePos RP = CheckRange(*I);
142 if (RP == AfterLoc)
143 return ASTLocation(D);
144 if (RP == ContainsLoc)
145 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000146 }
147
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000148 // We didn't find the location in the parameters and we didn't get passed it.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000149
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000150 if (!D->isThisDeclarationADefinition())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000151 return ASTLocation(D);
Argiris Kirtzidis4770f5e2009-07-05 22:21:17 +0000152
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000153 // Second, search through the declarations that are part of the function.
154 // If we find he location there, we won't have to search through its body.
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000155
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000156 for (DeclContext::decl_iterator
157 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
158 if (isa<ParmVarDecl>(*I))
159 continue; // We already searched through the parameters.
160
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000161 RangePos RP = CheckRange(*I);
162 if (RP == AfterLoc)
163 break;
164 if (RP == ContainsLoc)
165 return Visit(*I);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000166 }
Argiris Kirtzidis7283e462009-07-05 22:21:46 +0000167
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000168 // We didn't find a declaration that corresponds to the source location.
169
170 // Finally, search through the body of the function.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000171 Stmt *Body = D->getBody();
172 assert(Body && "Expected definition");
173 assert(CheckRange(Body) != BeforeLoc
174 && "This function is supposed to contain the loc");
175 if (CheckRange(Body) == AfterLoc)
176 return ASTLocation(D);
177
178 // The body contains the location.
179 assert(CheckRange(Body) == ContainsLoc);
180 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000181}
182
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000183ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
184 assert(CheckRange(D) == ContainsLoc
185 && "Should visit only after verifying that loc is in range");
186
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000187 // Check whether the location points to the init expression.
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000188 Expr *Init = D->getInit();
189 if (Init && CheckRange(Init) == ContainsLoc)
190 return StmtLocResolver(Ctx, Loc, D).Visit(Init);
191
192 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000193}
194
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000195ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
196 assert(CheckRange(D) == ContainsLoc
197 && "Should visit only after verifying that loc is in range");
198 return ASTLocation(D);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000199}
200
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000201LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000202 if (!Range.isValid())
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000203 return BeforeLoc; // Keep looking.
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000204
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000205 // Update the end source range to cover the full length of the token
206 // positioned at the end of the source range.
207 //
208 // e.g.,
209 // int foo
210 // ^ ^
211 //
212 // will be updated to
213 // int foo
214 // ^ ^
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000215 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
216 Ctx.getSourceManager(),
217 Ctx.getLangOptions());
218 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000219
220 SourceManager &SourceMgr = Ctx.getSourceManager();
221 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
222 return BeforeLoc;
223
224 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
225 return AfterLoc;
226
227 return ContainsLoc;
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000228}
229
230void LocResolverBase::print(Decl *D) {
231 llvm::raw_ostream &OS = llvm::outs();
232 OS << "#### DECL ####\n";
Argiris Kirtzidis9a6fb962009-06-30 02:35:04 +0000233 D->print(OS);
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000234 OS << " <";
235 D->getLocStart().print(OS, Ctx.getSourceManager());
236 OS << " > - <";
237 D->getLocEnd().print(OS, Ctx.getSourceManager());
238 OS << ">\n\n";
239 OS.flush();
240}
241
242void LocResolverBase::print(Stmt *Node) {
243 llvm::raw_ostream &OS = llvm::outs();
244 OS << "#### STMT ####\n";
Chris Lattner7099c782009-06-30 01:26:17 +0000245 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000246 OS << " <";
247 Node->getLocStart().print(OS, Ctx.getSourceManager());
248 OS << " > - <";
249 Node->getLocEnd().print(OS, Ctx.getSourceManager());
250 OS << ">\n\n";
251 OS.flush();
252}
253
254
255/// \brief Returns the AST node that a source location points to.
256///
Argiris Kirtzidis98eec712009-07-06 21:35:02 +0000257ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000258 if (Loc.isInvalid())
Argiris Kirtzidis2fcbc1e2009-07-06 21:34:20 +0000259 return ASTLocation();
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000260
Argiris Kirtzidis3ed07532009-07-07 00:53:31 +0000261 return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
Argiris Kirtzidis40bf2832009-06-25 18:22:41 +0000262}