1/*
2 * Copyright (C) 2008 Abderrahim Kitouni
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/* Finds the innermost block containing the given location */
19public class BlockLocator : Vala.CodeVisitor {
20	struct Location {
21		int line;
22		int column;
23		public Location (int line, int column) {
24			this.line = line;
25			this.column = column;
26		}
27		public bool inside (Vala.SourceReference src) {
28			var begin = Location (src.begin.line, src.begin.column);
29			var end = Location (src.end.line, src.end.column);
30
31			return begin.before (this) && this.before(end);
32		}
33		public bool before (Location other) {
34			if (line > other.line)
35				return false;
36			if (line == other.line && column > other.column)
37				return false;
38			return true;
39		}
40	}
41
42	Location location;
43	Vala.Symbol innermost;
44	Location innermost_begin;
45	Location innermost_end;
46
47	public Vala.Symbol locate (Vala.SourceFile file, int line, int column) {
48		location = Location (line, column);
49		innermost = null;
50		file.accept_children(this);
51		return innermost;
52	}
53
54	bool update_location (Vala.Symbol s) {
55		if (!location.inside (s.source_reference))
56			return false;
57
58		var begin = Location (s.source_reference.begin.line, s.source_reference.begin.column);
59		var end = Location (s.source_reference.end.line, s.source_reference.end.column);
60
61		if (innermost == null || (innermost_begin.before(begin) && end.before(innermost_end))) {
62				innermost = s;
63				innermost_begin = begin;
64				innermost_end = end;
65				return true;
66		}
67
68		return false;
69	}
70
71	public override void visit_block (Vala.Block b) {
72		if (update_location (b))
73			b.accept_children(this);
74	}
75
76	public override void visit_namespace (Vala.Namespace ns) {
77		update_location (ns);
78		ns.accept_children(this);
79	}
80	public override void visit_class (Vala.Class cl) {
81		/* the location of a class contains only its declaration, not its content */
82		if (update_location (cl))
83			return;
84		cl.accept_children(this);
85	}
86	public override void visit_struct (Vala.Struct st) {
87		if (update_location (st))
88			return;
89		st.accept_children(this);
90	}
91	public override void visit_interface (Vala.Interface iface) {
92		if (update_location (iface))
93			return;
94		iface.accept_children(this);
95	}
96
97	public override void visit_method (Vala.Method m) {
98		if (update_location (m))
99			return;
100		m.accept_children(this);
101	}
102	public override void visit_creation_method (Vala.CreationMethod m) {
103		if (update_location (m))
104			return;
105		m.accept_children(this);
106	}
107	public override void visit_property (Vala.Property prop) {
108		prop.accept_children(this);
109	}
110	public override void visit_property_accessor (Vala.PropertyAccessor acc) {
111		acc.accept_children(this);
112	}
113	public override void visit_constructor (Vala.Constructor c) {
114		c.accept_children(this);
115	}
116	public override void visit_destructor (Vala.Destructor d) {
117		d.accept_children(this);
118	}
119	public override void visit_if_statement (Vala.IfStatement stmt) {
120		stmt.accept_children(this);
121	}
122	public override void visit_switch_statement (Vala.SwitchStatement stmt) {
123		stmt.accept_children(this);
124	}
125	public override void visit_switch_section (Vala.SwitchSection section) {
126		visit_block (section);
127	}
128	public override void visit_while_statement (Vala.WhileStatement stmt) {
129		stmt.accept_children(this);
130	}
131	public override void visit_do_statement (Vala.DoStatement stmt) {
132		stmt.accept_children(this);
133	}
134	public override void visit_for_statement (Vala.ForStatement stmt) {
135		stmt.accept_children(this);
136	}
137	public override void visit_foreach_statement (Vala.ForeachStatement stmt) {
138		stmt.accept_children(this);
139	}
140	public override void visit_try_statement (Vala.TryStatement stmt) {
141		stmt.accept_children(this);
142	}
143	public override void visit_catch_clause (Vala.CatchClause clause) {
144		clause.accept_children(this);
145	}
146	public override void visit_lock_statement (Vala.LockStatement stmt) {
147		stmt.accept_children(this);
148	}
149	// go to lambda body directly if exists.
150	public override void visit_lambda_expression (Vala.LambdaExpression expr) {
151		if (expr.statement_body != null) {
152			if (update_location (expr.statement_body))
153				expr.statement_body.accept_children(this);
154		}
155		else
156			expr.accept_children (this);
157	}
158	public override void visit_expression_statement (Vala.ExpressionStatement stmt) {
159		stmt.accept_children (this);
160	}
161	public override void visit_method_call (Vala.MethodCall mc) {
162		mc.accept_children (this);
163	}
164	public override void visit_signal (Vala.Signal sig) {
165		sig.accept_children (this);
166	}
167}
168
169