blob: e93d689c04bcc36ddca86df8129cbe9d526a958a [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
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000011// source location into a ASTLocation.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000012//
13//===----------------------------------------------------------------------===//
14
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +000015#include "clang/Index/Utils.h"
Argyrios Kyrtzidisccbcb702009-07-06 21:34:47 +000016#include "clang/Index/ASTLocation.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;
Argyrios Kyrtzidisccbcb702009-07-06 21:34:47 +000023using namespace idx;
Argyrios Kyrtzidis53d4c142009-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;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000032
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000033 enum RangePos {
34 BeforeLoc,
35 ContainsLoc,
36 AfterLoc
37 };
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000038
Argyrios Kyrtzidisbd2ab6e2009-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()); }
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000042
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +000043 template <typename T>
44 bool isBeforeLocation(T *Node) {
45 return CheckRange(Node) == BeforeLoc;
46 }
47
48 template <typename T>
49 bool ContainsLocation(T *Node) {
50 return CheckRange(Node) == ContainsLoc;
51 }
52
53 template <typename T>
54 bool isAfterLocation(T *Node) {
55 return CheckRange(Node) == AfterLoc;
56 }
57
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000058public:
59 LocResolverBase(ASTContext &ctx, SourceLocation loc)
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000060 : Ctx(ctx), Loc(loc) {}
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000061
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000062 /// \brief Debugging output.
63 void print(Decl *D);
64 /// \brief Debugging output.
65 void print(Stmt *Node);
66};
67
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000068/// \brief Searches a statement for the ASTLocation that corresponds to a source
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000069/// location.
70class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000071 public StmtVisitor<StmtLocResolver,
72 ASTLocation > {
73 Decl *Parent;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000074
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000075public:
76 StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent)
77 : LocResolverBase(ctx, loc), Parent(parent) {}
78
79 ASTLocation VisitDeclStmt(DeclStmt *Node);
80 ASTLocation VisitStmt(Stmt *Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000081};
82
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000083/// \brief Searches a declaration for the ASTLocation that corresponds to a
84/// source location.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000085class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000086 public DeclVisitor<DeclLocResolver,
87 ASTLocation > {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000088public:
89 DeclLocResolver(ASTContext &ctx, SourceLocation loc)
90 : LocResolverBase(ctx, loc) {}
91
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +000092 ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU);
93 ASTLocation VisitVarDecl(VarDecl *D);
94 ASTLocation VisitFunctionDecl(FunctionDecl *D);
95 ASTLocation VisitDecl(Decl *D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +000096};
97
98} // anonymous namespace
99
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000100ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000101 assert(ContainsLocation(Node) &&
102 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000103
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000104 // Search all declarations of this DeclStmt.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000105 for (DeclStmt::decl_iterator
106 I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000107 RangePos RP = CheckRange(*I);
108 if (RP == AfterLoc)
109 break;
110 if (RP == ContainsLoc)
111 return DeclLocResolver(Ctx, Loc).Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000112 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000113
114 return ASTLocation(Parent, Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000115}
116
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000117ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000118 assert(ContainsLocation(Node) &&
119 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000120
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000121 // Search the child statements.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000122 for (Stmt::child_iterator
123 I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000124 RangePos RP = CheckRange(*I);
125 if (RP == AfterLoc)
126 break;
127 if (RP == ContainsLoc)
128 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000129 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000130
131 return ASTLocation(Parent, Node);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000132}
133
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000134ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
135 DeclContext *DC = TU;
136
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000137 for (DeclContext::decl_iterator
Argyrios Kyrtzidis17945a02009-06-30 02:36:12 +0000138 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000139 RangePos RP = CheckRange(*I);
140 if (RP == AfterLoc)
141 break;
142 if (RP == ContainsLoc)
143 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000144 }
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000145
146 return ASTLocation();
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000147}
148
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000149ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000150 assert(ContainsLocation(D) &&
151 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000152
153 // First, search through the parameters of the function.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000154 for (FunctionDecl::param_iterator
155 I = D->param_begin(), E = D->param_end(); I != E; ++I) {
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000156 RangePos RP = CheckRange(*I);
157 if (RP == AfterLoc)
158 return ASTLocation(D);
159 if (RP == ContainsLoc)
160 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000161 }
162
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000163 // We didn't find the location in the parameters and we didn't get passed it.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000164
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000165 if (!D->isThisDeclarationADefinition())
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000166 return ASTLocation(D);
Argyrios Kyrtzidis685477f2009-07-05 22:21:17 +0000167
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000168 // Second, search through the declarations that are part of the function.
169 // If we find he location there, we won't have to search through its body.
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000170
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000171 for (DeclContext::decl_iterator
172 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
173 if (isa<ParmVarDecl>(*I))
174 continue; // We already searched through the parameters.
175
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000176 RangePos RP = CheckRange(*I);
177 if (RP == AfterLoc)
178 break;
179 if (RP == ContainsLoc)
180 return Visit(*I);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000181 }
Argyrios Kyrtzidis07796e12009-07-05 22:21:46 +0000182
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000183 // We didn't find a declaration that corresponds to the source location.
184
185 // Finally, search through the body of the function.
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000186 Stmt *Body = D->getBody();
187 assert(Body && "Expected definition");
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000188 assert(!isBeforeLocation(Body) &&
189 "This function is supposed to contain the loc");
190 if (isAfterLocation(Body))
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000191 return ASTLocation(D);
192
193 // The body contains the location.
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000194 assert(ContainsLocation(Body));
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000195 return StmtLocResolver(Ctx, Loc, D).Visit(Body);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000196}
197
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000198ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000199 assert(ContainsLocation(D) &&
200 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000201
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000202 // Check whether the location points to the init expression.
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000203 Expr *Init = D->getInit();
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000204 if (Init && ContainsLocation(Init))
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000205 return StmtLocResolver(Ctx, Loc, D).Visit(Init);
206
207 return ASTLocation(D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000208}
209
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000210ASTLocation DeclLocResolver::VisitDecl(Decl *D) {
Argyrios Kyrtzidisa6488a12009-07-10 03:41:26 +0000211 assert(ContainsLocation(D) &&
212 "Should visit only after verifying that loc is in range");
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000213 return ASTLocation(D);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000214}
215
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000216LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000217 if (!Range.isValid())
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000218 return BeforeLoc; // Keep looking.
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000219
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000220 // Update the end source range to cover the full length of the token
221 // positioned at the end of the source range.
222 //
223 // e.g.,
224 // int foo
225 // ^ ^
226 //
227 // will be updated to
228 // int foo
229 // ^ ^
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000230 unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
231 Ctx.getSourceManager(),
232 Ctx.getLangOptions());
233 Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000234
235 SourceManager &SourceMgr = Ctx.getSourceManager();
236 if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
237 return BeforeLoc;
238
239 if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
240 return AfterLoc;
241
242 return ContainsLoc;
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000243}
244
245void LocResolverBase::print(Decl *D) {
246 llvm::raw_ostream &OS = llvm::outs();
247 OS << "#### DECL ####\n";
Argyrios Kyrtzidisf1d60ea2009-06-30 02:35:04 +0000248 D->print(OS);
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000249 OS << " <";
250 D->getLocStart().print(OS, Ctx.getSourceManager());
251 OS << " > - <";
252 D->getLocEnd().print(OS, Ctx.getSourceManager());
253 OS << ">\n\n";
254 OS.flush();
255}
256
257void LocResolverBase::print(Stmt *Node) {
258 llvm::raw_ostream &OS = llvm::outs();
259 OS << "#### STMT ####\n";
Chris Lattnere4f21422009-06-30 01:26:17 +0000260 Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000261 OS << " <";
262 Node->getLocStart().print(OS, Ctx.getSourceManager());
263 OS << " > - <";
264 Node->getLocEnd().print(OS, Ctx.getSourceManager());
265 OS << ">\n\n";
266 OS.flush();
267}
268
269
270/// \brief Returns the AST node that a source location points to.
271///
Argyrios Kyrtzidis818e15b2009-07-06 21:35:02 +0000272ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000273 if (Loc.isInvalid())
Argyrios Kyrtzidis874012b2009-07-06 21:34:20 +0000274 return ASTLocation();
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000275
Argyrios Kyrtzidisbd2ab6e2009-07-07 00:53:31 +0000276 return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidis53d4c142009-06-25 18:22:41 +0000277}