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