LCOV - code coverage report
Current view: top level - vala - valaflowanalyzer.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 96.9 % 645 625
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valaflowanalyzer.vala
       2              :  *
       3              :  * Copyright (C) 2008-2010  Jürg Billeter
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Lesser General Public
       7              :  * License as published by the Free Software Foundation; either
       8              :  * version 2.1 of the License, or (at your option) any later version.
       9              : 
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Lesser General Public License for more details.
      14              : 
      15              :  * You should have received a copy of the GNU Lesser General Public
      16              :  * License along with this library; if not, write to the Free Software
      17              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25              : /**
      26              :  * Code visitor building the control flow graph.
      27              :  */
      28         4614 : public class Vala.FlowAnalyzer : CodeVisitor {
      29       980410 :         private class JumpTarget {
      30        22749 :                 public bool is_break_target { get; set; }
      31        10034 :                 public bool is_continue_target { get; set; }
      32       313300 :                 public bool is_return_target { get; set; }
      33        96424 :                 public bool is_exit_target { get; set; }
      34         4326 :                 public bool is_error_target { get; set; }
      35       219575 :                 public ErrorDomain? error_domain { get; set; }
      36       211260 :                 public ErrorCode? error_code { get; set; }
      37       209243 :                 public Class? error_class { get; set; }
      38       111861 :                 public bool is_finally_clause { get; set; }
      39       751156 :                 public BasicBlock basic_block { get; set; }
      40       207269 :                 public BasicBlock? last_block { get; set; }
      41       215445 :                 public CatchClause? catch_clause { get; set; }
      42              : 
      43        29328 :                 public JumpTarget.break_target (BasicBlock basic_block) {
      44         9776 :                         this.basic_block = basic_block;
      45         9776 :                         is_break_target = true;
      46              :                 }
      47              : 
      48        29016 :                 public JumpTarget.continue_target (BasicBlock basic_block) {
      49         9672 :                         this.basic_block = basic_block;
      50         9672 :                         is_continue_target = true;
      51              :                 }
      52              : 
      53       278358 :                 public JumpTarget.return_target (BasicBlock basic_block) {
      54        92786 :                         this.basic_block = basic_block;
      55        92786 :                         is_return_target = true;
      56              :                 }
      57              : 
      58       278358 :                 public JumpTarget.exit_target (BasicBlock basic_block) {
      59        92786 :                         this.basic_block = basic_block;
      60        92786 :                         is_exit_target = true;
      61              :                 }
      62              : 
      63         6207 :                 public JumpTarget.error_target (BasicBlock basic_block, CatchClause catch_clause, ErrorDomain? error_domain, ErrorCode? error_code, Class? error_class) {
      64         2069 :                         this.basic_block = basic_block;
      65         2069 :                         this.catch_clause = catch_clause;
      66         2069 :                         this.error_domain = error_domain;
      67         2069 :                         this.error_code = error_code;
      68         2069 :                         this.error_class = error_class;
      69         2069 :                         is_error_target = true;
      70              :                 }
      71              : 
      72          132 :                 public JumpTarget.any_target (BasicBlock basic_block) {
      73           44 :                         this.basic_block = basic_block;
      74           44 :                         is_break_target = true;
      75           44 :                         is_continue_target = true;
      76           44 :                         is_return_target = true;
      77           44 :                         is_exit_target = true;
      78           44 :                         is_error_target = true;
      79              :                 }
      80              : 
      81          123 :                 public JumpTarget.finally_clause (BasicBlock basic_block, BasicBlock last_block) {
      82           41 :                         this.basic_block = basic_block;
      83           41 :                         this.last_block = last_block;
      84           41 :                         is_finally_clause = true;
      85              :                 }
      86              :         }
      87              : 
      88         1538 :         private CodeContext context;
      89         1538 :         private BasicBlock current_block;
      90              :         private bool unreachable_reported;
      91         3076 :         private List<JumpTarget> jump_stack = new ArrayList<JumpTarget> ();
      92         1538 :         private Set<BasicBlock> all_basic_blocks;
      93              : 
      94              :         // check_variables
      95         1538 :         Map<Symbol, List<Variable>> var_map;
      96         1538 :         Set<Variable> used_vars;
      97         1538 :         Map<Variable, PhiFunction> phi_functions;
      98              : 
      99         3076 :         public FlowAnalyzer () {
     100              :         }
     101              : 
     102              :         /**
     103              :          * Build control flow graph in the specified context.
     104              :          *
     105              :          * @param context a code context
     106              :          */
     107         1942 :         public void analyze (CodeContext context) {
     108          971 :                 this.context = context;
     109          971 :                 all_basic_blocks = new HashSet<BasicBlock> ();
     110              : 
     111        11469 :                 var source_files = context.get_source_files ();
     112        10117 :                 foreach (SourceFile file in source_files) {
     113         4573 :                         file.accept (this);
     114              :                 }
     115              : 
     116          971 :                 all_basic_blocks = null;
     117          971 :                 this.context = null;
     118              :         }
     119              : 
     120         4573 :         public override void visit_source_file (SourceFile source_file) {
     121         4573 :                 source_file.accept_children (this);
     122              :         }
     123              : 
     124       239165 :         public override void visit_class (Class cl) {
     125       239165 :                 cl.accept_children (this);
     126              :         }
     127              : 
     128        91821 :         public override void visit_struct (Struct st) {
     129        91821 :                 st.accept_children (this);
     130              :         }
     131              : 
     132        36883 :         public override void visit_interface (Interface iface) {
     133        36883 :                 iface.accept_children (this);
     134              :         }
     135              : 
     136       133983 :         public override void visit_enum (Enum en) {
     137       133983 :                 en.accept_children (this);
     138              :         }
     139              : 
     140        19456 :         public override void visit_error_domain (ErrorDomain ed) {
     141        19456 :                 ed.accept_children (this);
     142              :         }
     143              : 
     144       379873 :         public override void visit_field (Field f) {
     145       379873 :                 if (f.is_internal_symbol () && !f.used && !f.external_package) {
     146           85 :                         if (!f.is_private_symbol () && (context.internal_header_filename != null || context.use_fast_vapi)) {
     147              :                                 // do not warn if internal member may be used outside this compilation unit
     148              :                         } else {
     149           85 :                                 Report.warning (f.source_reference, "Field `%s' never used", f.get_full_name ());
     150              :                         }
     151              :                 }
     152              :         }
     153              : 
     154         8404 :         public override void visit_lambda_expression (LambdaExpression le) {
     155      3102435 :                 var old_current_block = current_block;
     156         4202 :                 var old_unreachable_reported = unreachable_reported;
     157         4202 :                 var old_jump_stack = jump_stack;
     158         4202 :                 mark_unreachable ();
     159         4202 :                 jump_stack = new ArrayList<JumpTarget> ();
     160              : 
     161         4202 :                 le.accept_children (this);
     162              : 
     163         8404 :                 current_block = old_current_block;
     164         4202 :                 unreachable_reported = old_unreachable_reported;
     165         8404 :                 jump_stack = old_jump_stack;
     166              :         }
     167              : 
     168      4172621 :         public override void visit_method (Method m) {
     169      4172621 :                 if (m.is_internal_symbol () && !m.used && !m.entry_point && !m.external_package
     170          421 :                     && !m.overrides && (m.base_interface_method == null || m.base_interface_method == m)
     171          256 :                     && !(m is CreationMethod)) {
     172          121 :                         if (!m.is_private_symbol () && (context.internal_header_filename != null || context.use_fast_vapi)) {
     173              :                                 // do not warn if internal member may be used outside this compilation unit
     174          161 :                         } else if (m.parent_symbol != null && m.parent_symbol.has_attribute ("DBus")
     175           40 :                             && m.get_attribute_bool ("DBus", "visible", true)) {
     176              :                                 // do not warn if internal member is a visible DBus method
     177              :                         } else {
     178           81 :                                 Report.warning (m.source_reference, "Method `%s' never used", m.get_full_name ());
     179              :                         }
     180              :                 }
     181              : 
     182      4172621 :                 visit_subroutine (m);
     183              :         }
     184              : 
     185        88501 :         public override void visit_signal (Signal sig) {
     186        88501 :                 if (sig.default_handler != null) {
     187        76762 :                         visit_subroutine (sig.default_handler);
     188              :                 }
     189              :         }
     190              : 
     191      4740414 :         void visit_subroutine (Subroutine m) {
     192      4740414 :                 if (m.body == null) {
     193              :                         return;
     194              :                 }
     195              : 
     196        92786 :                 m.entry_block = new BasicBlock.entry ();
     197        92786 :                 all_basic_blocks.add (m.entry_block);
     198        92786 :                 m.return_block = new BasicBlock ();
     199        92786 :                 all_basic_blocks.add (m.return_block);
     200        92786 :                 m.exit_block = new BasicBlock.exit ();
     201        92786 :                 all_basic_blocks.add (m.exit_block);
     202              : 
     203        92786 :                 m.return_block.connect (m.exit_block);
     204              : 
     205        92786 :                 if (m is Method) {
     206              :                         // ensure out parameters are defined at end of method
     207       343318 :                         foreach (var param in ((Method) m).get_parameters ()) {
     208       147098 :                                 if (param.direction == ParameterDirection.OUT) {
     209        19359 :                                         var param_ma = new MemberAccess.simple (param.name, param.source_reference);
     210        19359 :                                         param_ma.symbol_reference = param;
     211        19359 :                                         m.return_block.add_node (param_ma);
     212              :                                 }
     213              :                         }
     214              :                 }
     215              : 
     216        92786 :                 current_block = new BasicBlock ();
     217        92786 :                 all_basic_blocks.add (current_block);
     218              : 
     219        92786 :                 m.entry_block.connect (current_block);
     220        92786 :                 current_block.add_node (m);
     221              : 
     222        92786 :                 jump_stack.add (new JumpTarget.return_target (m.return_block));
     223        92786 :                 jump_stack.add (new JumpTarget.exit_target (m.exit_block));
     224              : 
     225        92786 :                 m.accept_children (this);
     226              : 
     227        92786 :                 jump_stack.remove_at (jump_stack.size - 1);
     228              : 
     229        92786 :                 if (current_block != null) {
     230              :                         // end of method body reachable
     231              : 
     232        12220 :                         if (m.has_result) {
     233            1 :                                 Report.error (m.source_reference, "missing return statement at end of subroutine body");
     234            1 :                                 m.error = true;
     235              :                         }
     236              : 
     237        12220 :                         current_block.connect (m.return_block);
     238              :                 } else {
     239        80566 :                         m.body.unreachable_exit = true;
     240              :                 }
     241              : 
     242        92786 :                 analyze_body (m.entry_block);
     243              :         }
     244              : 
     245       185572 :         void analyze_body (BasicBlock entry_block) {
     246        92786 :                 var block_list = get_depth_first_list (entry_block);
     247              : 
     248        92786 :                 build_dominator_tree (block_list, entry_block);
     249        92786 :                 build_dominator_frontier (block_list, entry_block);
     250        92786 :                 insert_phi_functions (block_list, entry_block);
     251        92786 :                 check_variables (entry_block);
     252              :         }
     253              : 
     254              :         // generates reverse postorder list
     255        92786 :         List<BasicBlock> get_depth_first_list (BasicBlock entry_block) {
     256        92786 :                 var list = new ArrayList<BasicBlock> ();
     257        92786 :                 depth_first_traverse (entry_block, list);
     258        92786 :                 return list;
     259              :         }
     260              : 
     261       758342 :         void depth_first_traverse (BasicBlock current, List<BasicBlock> list) {
     262       758342 :                 if (current.postorder_visited) {
     263              :                         return;
     264              :                 }
     265       659518 :                 current.postorder_visited = true;
     266      1325074 :                 foreach (weak BasicBlock succ in current.get_successors ()) {
     267       665556 :                         depth_first_traverse (succ, list);
     268              :                 }
     269       659518 :                 current.postorder_number = list.size;
     270       659518 :                 list.insert (0, current);
     271              :         }
     272              : 
     273       185572 :         void build_dominator_tree (List<BasicBlock> block_list, BasicBlock entry_block) {
     274              :                 // immediate dominators
     275        92786 :                 var idoms = new BasicBlock[block_list.size];
     276        92786 :                 idoms[entry_block.postorder_number] = entry_block;
     277              : 
     278        92786 :                 bool changed = true;
     279       286668 :                 while (changed) {
     280       193882 :                         changed = false;
     281      2963692 :                         foreach (BasicBlock block in block_list) {
     282      1481846 :                                 if (block == entry_block) {
     283       193882 :                                         continue;
     284              :                                 }
     285              : 
     286              :                                 // new immediate dominator
     287      1287964 :                                 BasicBlock new_idom = null;
     288      1287964 :                                 bool first = true;
     289      2811535 :                                 foreach (weak BasicBlock pred in block.get_predecessors ()) {
     290      1523571 :                                         if (idoms[pred.postorder_number] != null) {
     291      1513774 :                                                 if (first) {
     292      2575928 :                                                         new_idom = pred;
     293              :                                                         first = false;
     294              :                                                 } else {
     295       225810 :                                                         new_idom = intersect (idoms, pred, new_idom);
     296              :                                                 }
     297              :                                         }
     298              :                                 }
     299      1287964 :                                 if (idoms[block.postorder_number] != new_idom) {
     300      1170966 :                                         idoms[block.postorder_number] = new_idom;
     301       585483 :                                         changed = true;
     302              :                                 }
     303              :                         }
     304              :                 }
     305              : 
     306              :                 // build tree
     307      1319036 :                 foreach (BasicBlock block in block_list) {
     308       659518 :                         if (block == entry_block) {
     309        92786 :                                 continue;
     310              :                         }
     311              : 
     312       566732 :                         idoms[block.postorder_number].add_child (block);
     313              :                 }
     314              :         }
     315              : 
     316       225810 :         BasicBlock intersect (BasicBlock[] idoms, BasicBlock b1, BasicBlock b2) {
     317       645724 :                 while (b1 != b2) {
     318       645468 :                         while (b1.postorder_number < b2.postorder_number) {
     319       225554 :                                 b1 = idoms[b2.postorder_number];
     320              :                         }
     321       842152 :                         while (b2.postorder_number < b1.postorder_number) {
     322       422238 :                                 b2 = idoms[b2.postorder_number];
     323              :                         }
     324              :                 }
     325       225810 :                 return b1;
     326              :         }
     327              : 
     328        92786 :         void build_dominator_frontier (List<BasicBlock> block_list, BasicBlock entry_block) {
     329      1411822 :                 for (int i = block_list.size - 1; i >= 0; i--) {
     330       659518 :                         var block = block_list[i];
     331              : 
     332      1325074 :                         foreach (weak BasicBlock succ in block.get_successors ()) {
     333              :                                 // if idom(succ) != block
     334       665556 :                                 if (succ.parent != block) {
     335       194123 :                                         block.add_dominator_frontier (succ);
     336              :                                 }
     337              :                         }
     338              : 
     339      1226250 :                         foreach (weak BasicBlock child in block.get_children ()) {
     340      1453992 :                                 foreach (weak BasicBlock child_frontier in child.get_dominator_frontier ()) {
     341              :                                         // if idom(child_frontier) != block
     342       320528 :                                         if (child_frontier.parent != block) {
     343       213309 :                                                 block.add_dominator_frontier (child_frontier);
     344              :                                         }
     345              :                                 }
     346              :                         }
     347              :                 }
     348              :         }
     349              : 
     350        92786 :         Map<Variable, Set<BasicBlock>> get_assignment_map (List<BasicBlock> block_list, BasicBlock entry_block) {
     351        92786 :                 var map = new HashMap<Variable, Set<BasicBlock>> ();
     352      1411822 :                 foreach (BasicBlock block in block_list) {
     353       659518 :                         var defined_variables = new ArrayList<Variable> ();
     354      1966390 :                         foreach (CodeNode node in block.get_nodes ()) {
     355       653436 :                                 node.get_defined_variables (defined_variables);
     356              :                         }
     357              : 
     358      1059874 :                         foreach (Variable variable in defined_variables) {
     359       200178 :                                 var block_set = map.get (variable);
     360       200178 :                                 if (block_set == null) {
     361       126291 :                                         block_set = new HashSet<BasicBlock> ();
     362       126291 :                                         map.set (variable, block_set);
     363              :                                 }
     364       200178 :                                 block_set.add (block);
     365              :                         }
     366              :                 }
     367              :                 return map;
     368              :         }
     369              : 
     370       185572 :         void insert_phi_functions (List<BasicBlock> block_list, BasicBlock entry_block) {
     371        92786 :                 var assign = get_assignment_map (block_list, entry_block);
     372              : 
     373        92786 :                 int counter = 0;
     374        92786 :                 var work_list = new ArrayList<BasicBlock> ();
     375              : 
     376        92786 :                 var added = new HashMap<BasicBlock, int> ();
     377        92786 :                 var phi = new HashMap<BasicBlock, int> ();
     378      1411822 :                 foreach (BasicBlock block in block_list) {
     379       659518 :                         added.set (block, 0);
     380       659518 :                         phi.set (block, 0);
     381              :                 }
     382              : 
     383       438154 :                 foreach (Variable variable in assign.get_keys ()) {
     384       126291 :                         counter++;
     385       450251 :                         foreach (BasicBlock block in assign.get (variable)) {
     386       197669 :                                 work_list.add (block);
     387       197669 :                                 added.set (block, counter);
     388              :                         }
     389      1043919 :                         while (work_list.size > 0) {
     390       458814 :                                 BasicBlock block = work_list.remove_at (0);
     391      1647466 :                                 foreach (BasicBlock frontier in block.get_dominator_frontier ()) {
     392       364919 :                                         int blockPhi = phi.get (frontier);
     393       364919 :                                         if (blockPhi < counter) {
     394       267509 :                                                 frontier.add_phi_function (new PhiFunction (variable, frontier.get_predecessors ().size));
     395       267509 :                                                 phi.set (frontier, counter);
     396       267509 :                                                 int block_added = added.get (frontier);
     397       267509 :                                                 if (block_added < counter) {
     398       261145 :                                                         added.set (frontier, counter);
     399       261145 :                                                         work_list.add (frontier);
     400              :                                                 }
     401              :                                         }
     402              :                                 }
     403              :                         }
     404              :                 }
     405              :         }
     406              : 
     407       185572 :         void check_variables (BasicBlock entry_block) {
     408        92786 :                 var_map = new HashMap<Symbol, List<Variable>>();
     409        92786 :                 used_vars = new HashSet<Variable> ();
     410        92786 :                 phi_functions = new HashMap<Variable, PhiFunction> ();
     411              : 
     412        92786 :                 check_block_variables (entry_block);
     413              : 
     414              :                 // check for variables used before initialization
     415        92786 :                 var used_vars_queue = new ArrayList<Variable> ();
     416       494304 :                 foreach (Variable variable in used_vars) {
     417       154366 :                         used_vars_queue.add (variable);
     418              :                 }
     419       711484 :                 while (used_vars_queue.size > 0) {
     420       309349 :                         Variable used_var = used_vars_queue.remove_at (0);
     421              : 
     422       309349 :                         PhiFunction phi = phi_functions.get (used_var);
     423       309349 :                         if (phi != null) {
     424       602021 :                                 foreach (Variable variable in phi.operands) {
     425       241266 :                                         if (variable == null) {
     426            2 :                                                 if (used_var is LocalVariable) {
     427            2 :                                                         Report.error (used_var.source_reference, "Use of possibly unassigned local variable `%s'", used_var.name);
     428              :                                                 } else {
     429              :                                                         // parameter
     430            0 :                                                         Report.warning (used_var.source_reference, "Use of possibly unassigned parameter `%s'", used_var.name);
     431              :                                                 }
     432            2 :                                                 continue;
     433              :                                         }
     434       241264 :                                         if (!(variable in used_vars)) {
     435       154983 :                                                 variable.source_reference = used_var.source_reference;
     436       154983 :                                                 used_vars.add (variable);
     437       154983 :                                                 used_vars_queue.add (variable);
     438              :                                         }
     439              :                                 }
     440              :                         }
     441              :                 }
     442              : 
     443        92786 :                 phi_functions = null;
     444        92786 :                 used_vars = null;
     445        92786 :                 var_map = null;
     446              :         }
     447              : 
     448       659518 :         void check_block_variables (BasicBlock block) {
     449      1854054 :                 foreach (PhiFunction phi in block.get_phi_functions ()) {
     450       267509 :                         Variable versioned_var = process_assignment (var_map, phi.original_variable);
     451              : 
     452       267509 :                         phi_functions.set (versioned_var, phi);
     453              :                 }
     454              : 
     455      1966390 :                 foreach (CodeNode node in block.get_nodes ()) {
     456       653436 :                         var used_variables = new ArrayList<Variable> ();
     457       653436 :                         node.get_used_variables (used_variables);
     458              : 
     459      1129752 :                         foreach (Variable var_symbol in used_variables) {
     460       238162 :                                 var variable_stack = var_map.get (var_symbol);
     461       238162 :                                 if (variable_stack == null || variable_stack.size == 0) {
     462            8 :                                         if (var_symbol is LocalVariable) {
     463            4 :                                                 Report.error (node.source_reference, "Use of possibly unassigned local variable `%s'", var_symbol.name);
     464              :                                         } else {
     465              :                                                 // parameter
     466            4 :                                                 Report.warning (node.source_reference, "Use of possibly unassigned parameter `%s'", var_symbol.name);
     467              :                                         }
     468            8 :                                         continue;
     469              :                                 }
     470       238154 :                                 var versioned_variable = variable_stack.get (variable_stack.size - 1);
     471       238154 :                                 if (!(versioned_variable in used_vars)) {
     472       154366 :                                         versioned_variable.source_reference = node.source_reference;
     473              :                                 }
     474       238154 :                                 used_vars.add (versioned_variable);
     475              :                         }
     476              : 
     477       653436 :                         var defined_variables = new ArrayList<Variable> ();
     478       653436 :                         node.get_defined_variables (defined_variables);
     479              : 
     480      1053792 :                         foreach (Variable variable in defined_variables) {
     481       200178 :                                 process_assignment (var_map, variable);
     482              :                         }
     483              :                 }
     484              : 
     485      1325074 :                 foreach (weak BasicBlock succ in block.get_successors ()) {
     486       665556 :                         int j = 0;
     487       773665 :                         foreach (weak BasicBlock pred in succ.get_predecessors ()) {
     488       773665 :                                 if (pred == block) {
     489              :                                         break;
     490              :                                 }
     491       108109 :                                 j++;
     492              :                         }
     493              : 
     494      2466614 :                         foreach (PhiFunction phi in succ.get_phi_functions ()) {
     495       567751 :                                 var variable_stack = var_map.get (phi.original_variable);
     496       567751 :                                 if (variable_stack != null && variable_stack.size > 0) {
     497       508197 :                                         phi.operands.set (j, variable_stack.get (variable_stack.size - 1));
     498              :                                 }
     499              :                         }
     500              :                 }
     501              : 
     502      1226250 :                 foreach (weak BasicBlock child in block.get_children ()) {
     503       566732 :                         check_block_variables (child);
     504              :                 }
     505              : 
     506      1854054 :                 foreach (PhiFunction phi in block.get_phi_functions ()) {
     507       267509 :                         var variable_stack = var_map.get (phi.original_variable);
     508       267509 :                         variable_stack.remove_at (variable_stack.size - 1);
     509              :                 }
     510      1966390 :                 foreach (CodeNode node in block.get_nodes ()) {
     511       653436 :                         var defined_variables = new ArrayList<Variable> ();
     512       653436 :                         node.get_defined_variables (defined_variables);
     513              : 
     514      1053792 :                         foreach (Variable variable in defined_variables) {
     515       200178 :                                 var variable_stack = var_map.get (variable);
     516       200178 :                                 variable_stack.remove_at (variable_stack.size - 1);
     517              :                         }
     518              :                 }
     519              :         }
     520              : 
     521       467687 :         Variable process_assignment (Map<Symbol, List<Variable>> var_map, Variable var_symbol) {
     522       467687 :                 var variable_stack = var_map.get (var_symbol);
     523       467687 :                 if (variable_stack == null) {
     524       126291 :                         variable_stack = new ArrayList<Variable> ();
     525       126291 :                         var_map.set (var_symbol, variable_stack);
     526       126291 :                         var_symbol.single_assignment = true;
     527              :                 } else {
     528       341396 :                         var_symbol.single_assignment = false;
     529              :                 }
     530              :                 Variable versioned_var;
     531       467687 :                 if (var_symbol is LocalVariable) {
     532       407749 :                         versioned_var = new LocalVariable (var_symbol.variable_type.copy (), var_symbol.name, null, var_symbol.source_reference);
     533              :                 } else {
     534              :                         // parameter
     535        59938 :                         versioned_var = new Parameter (var_symbol.name, var_symbol.variable_type.copy (), var_symbol.source_reference);
     536              :                 }
     537       467687 :                 variable_stack.add (versioned_var);
     538       467687 :                 return versioned_var;
     539              :         }
     540              : 
     541       360217 :         public override void visit_creation_method (CreationMethod m) {
     542       360217 :                 visit_method (m);
     543              :         }
     544              : 
     545       290512 :         public override void visit_property (Property prop) {
     546       290512 :                 prop.accept_children (this);
     547              :         }
     548              : 
     549       491031 :         public override void visit_property_accessor (PropertyAccessor acc) {
     550       491031 :                 visit_subroutine (acc);
     551              :         }
     552              : 
     553       273412 :         public override void visit_block (Block b) {
     554       273412 :                 b.accept_children (this);
     555              :         }
     556              : 
     557       104695 :         public override void visit_declaration_statement (DeclarationStatement stmt) {
     558       104695 :                 stmt.accept_children (this);
     559              : 
     560       104695 :                 if (unreachable (stmt)) {
     561            1 :                         stmt.declaration.unreachable = true;
     562            1 :                         return;
     563              :                 }
     564              : 
     565       104694 :                 if (!stmt.declaration.used) {
     566          197 :                         Report.warning (stmt.declaration.source_reference, "Local variable `%s' declared but never used", stmt.declaration.name);
     567              :                 }
     568              : 
     569       104694 :                 current_block.add_node (stmt);
     570              : 
     571       104694 :                 unowned LocalVariable? local = stmt.declaration as LocalVariable;
     572       104677 :                 if (local != null && local.initializer != null) {
     573        58236 :                         handle_errors (local.initializer);
     574              :                 }
     575              :         }
     576              : 
     577       104692 :         public override void visit_local_variable (LocalVariable local) {
     578       104692 :                 if (local.initializer != null) {
     579        58236 :                         local.initializer.accept (this);
     580              :                 }
     581              :         }
     582              : 
     583       215320 :         public override void visit_expression_statement (ExpressionStatement stmt) {
     584       215320 :                 stmt.accept_children (this);
     585              : 
     586       215320 :                 if (unreachable (stmt)) {
     587              :                         return;
     588              :                 }
     589              : 
     590       215294 :                 current_block.add_node (stmt);
     591              : 
     592       215294 :                 handle_errors (stmt);
     593              : 
     594       215294 :                 if (stmt.expression is MethodCall) {
     595        66239 :                         unowned MethodCall expr = (MethodCall) stmt.expression;
     596        66239 :                         unowned MemberAccess? ma = expr.call as MemberAccess;
     597        65664 :                         if (ma != null && ma.symbol_reference != null && ma.symbol_reference.has_attribute ("NoReturn")) {
     598          213 :                                 mark_unreachable ();
     599          213 :                                 return;
     600              :                         }
     601              :                 }
     602              :         }
     603              : 
     604           36 :         public override void visit_with_statement (WithStatement stmt) {
     605           36 :                 if (unreachable (stmt)) {
     606              :                         return;
     607              :                 }
     608              : 
     609           35 :                 current_block.add_node (stmt.expression);
     610              : 
     611           35 :                 handle_errors (stmt.expression);
     612              : 
     613           35 :                 stmt.body.accept_children (this);
     614              :         }
     615              : 
     616       191477 :         public override void visit_if_statement (IfStatement stmt) {
     617        95739 :                 if (unreachable (stmt)) {
     618              :                         return;
     619              :                 }
     620              : 
     621              :                 // condition
     622        95738 :                 current_block.add_node (stmt.condition);
     623              : 
     624        95738 :                 handle_errors (stmt.condition);
     625              : 
     626              :                 // true block
     627        95738 :                 var last_block = current_block;
     628        95738 :                 if (stmt.condition.is_always_false ()) {
     629            7 :                         mark_unreachable ();
     630              :                 } else {
     631        95731 :                         current_block = new BasicBlock ();
     632        95731 :                         all_basic_blocks.add (current_block);
     633        95731 :                         last_block.connect (current_block);
     634              :                 }
     635        95738 :                 stmt.true_statement.accept (this);
     636              : 
     637              :                 // false block
     638        95738 :                 var last_true_block = current_block;
     639        95738 :                 if (stmt.condition.is_always_true ()) {
     640            9 :                         mark_unreachable ();
     641              :                 } else {
     642        95729 :                         current_block = new BasicBlock ();
     643        95729 :                         all_basic_blocks.add (current_block);
     644        95729 :                         last_block.connect (current_block);
     645              :                 }
     646        95738 :                 if (stmt.false_statement != null) {
     647        65763 :                         stmt.false_statement.accept (this);
     648              :                 }
     649              : 
     650              :                 // after if/else
     651        95738 :                 var last_false_block = current_block;
     652              :                 // reachable?
     653        95738 :                 if (last_true_block != null || last_false_block != null) {
     654        72344 :                         current_block = new BasicBlock ();
     655        72344 :                         all_basic_blocks.add (current_block);
     656        72344 :                         if (last_true_block != null) {
     657        57640 :                                 last_true_block.connect (current_block);
     658              :                         }
     659        72344 :                         if (last_false_block != null) {
     660        70332 :                                 last_false_block.connect (current_block);
     661              :                         }
     662              :                 }
     663              :         }
     664              : 
     665          208 :         public override void visit_switch_statement (SwitchStatement stmt) {
     666          104 :                 if (unreachable (stmt)) {
     667              :                         return;
     668              :                 }
     669              : 
     670          104 :                 var after_switch_block = new BasicBlock ();
     671          104 :                 all_basic_blocks.add (after_switch_block);
     672          104 :                 jump_stack.add (new JumpTarget.break_target (after_switch_block));
     673              : 
     674              :                 // condition
     675          104 :                 current_block.add_node (stmt.expression);
     676          104 :                 var condition_block = current_block;
     677              : 
     678          104 :                 handle_errors (stmt.expression);
     679              : 
     680          104 :                 bool has_default_label = false;
     681          208 :                 bool is_enum_typed = stmt.expression.value_type is EnumValueType;
     682              : 
     683          104 :                 unowned Enum? en = null;
     684           39 :                 HashSet<unowned EnumValue>? enum_values = null;
     685           65 :                 if (is_enum_typed) {
     686           39 :                         en = (Enum) ((EnumValueType) stmt.expression.value_type).type_symbol;
     687           39 :                         enum_values = new HashSet<unowned EnumValue> (direct_hash, direct_equal);
     688              :                 }
     689              : 
     690         1232 :                 foreach (SwitchSection section in stmt.get_sections ()) {
     691          564 :                         current_block = new BasicBlock ();
     692          564 :                         all_basic_blocks.add (current_block);
     693          564 :                         condition_block.connect (current_block);
     694         4960 :                         foreach (Statement section_stmt in section.get_statements ()) {
     695         2198 :                                 section_stmt.accept (this);
     696              :                         }
     697              : 
     698          564 :                         if (is_enum_typed) {
     699          842 :                                 foreach (SwitchLabel label in section.get_labels ()) {
     700          287 :                                         if (label.expression != null) {
     701          257 :                                                 unowned EnumValue? val = label.expression.symbol_reference as EnumValue;
     702          287 :                                                 if (val != null) {
     703          257 :                                                         enum_values.add (val);
     704              :                                                 }
     705              :                                         }
     706              :                                 }
     707              :                         }
     708              : 
     709          564 :                         if (section.has_default_label ()) {
     710           71 :                                 has_default_label = true;
     711              :                         }
     712              : 
     713          564 :                         if (current_block != null) {
     714              :                                 // end of switch section reachable
     715              :                                 // we don't allow fall-through
     716              : 
     717            1 :                                 Report.error (section.source_reference, "missing break statement at end of switch section");
     718            1 :                                 section.error = true;
     719              : 
     720            1 :                                 current_block.connect (after_switch_block);
     721              :                         }
     722              :                 }
     723              : 
     724          113 :                 if (!has_default_label && is_enum_typed) {
     725              :                         // Check if enum-based switching as fully covered, and if so,
     726              :                         // handle it like there was a default-label given
     727              : 
     728            9 :                         HashSet<EnumValue> remaining_values = new HashSet<EnumValue> ();
     729            9 :                         remaining_values.add_all (en.get_values ());
     730           85 :                         foreach (unowned EnumValue val in enum_values) {
     731           76 :                                 remaining_values.remove (val);
     732              :                         }
     733           11 :                         if (remaining_values.size > 0) {
     734            2 :                                 string[] missing_vals = {};
     735            8 :                                 foreach (var val in remaining_values) {
     736            6 :                                         missing_vals += val.name;
     737              :                                 }
     738            2 :                                 Report.warning (stmt.source_reference, "Switch does not handle `%s' of enum `%s'", string.joinv ("', `", missing_vals), en.get_full_name ());
     739              :                         }
     740              :                 }
     741              : 
     742          104 :                 if (!has_default_label) {
     743           33 :                         condition_block.connect (after_switch_block);
     744              :                 }
     745              : 
     746              :                 // after switch
     747              :                 // reachable?
     748          104 :                 if (after_switch_block.get_predecessors ().size > 0) {
     749          184 :                         current_block = after_switch_block;
     750              :                 } else {
     751           12 :                         mark_unreachable ();
     752              :                 }
     753              : 
     754          104 :                 jump_stack.remove_at (jump_stack.size - 1);
     755              :         }
     756              : 
     757        19010 :         public override void visit_loop_statement (LoopStatement stmt) {
     758         9505 :                 if (unreachable (stmt)) {
     759              :                         return;
     760              :                 }
     761              : 
     762         9505 :                 var loop_block = new BasicBlock ();
     763         9505 :                 all_basic_blocks.add (loop_block);
     764         9505 :                 jump_stack.add (new JumpTarget.continue_target (loop_block));
     765         9505 :                 var after_loop_block = new BasicBlock ();
     766         9505 :                 all_basic_blocks.add (after_loop_block);
     767         9505 :                 jump_stack.add (new JumpTarget.break_target (after_loop_block));
     768              : 
     769              :                 // loop block
     770         9505 :                 var last_block = current_block;
     771         9505 :                 last_block.connect (loop_block);
     772        19010 :                 current_block = loop_block;
     773              : 
     774         9505 :                 stmt.body.accept (this);
     775              :                 // end of loop block reachable?
     776         9505 :                 if (current_block != null) {
     777         9477 :                         current_block.connect (loop_block);
     778              :                 }
     779              : 
     780              :                 // after loop
     781              :                 // reachable?
     782         9505 :                 if (after_loop_block.get_predecessors ().size == 0) {
     783              :                         // after loop block not reachable
     784            4 :                         mark_unreachable ();
     785              :                 } else {
     786              :                         // after loop block reachable
     787        19002 :                         current_block = after_loop_block;
     788              :                 }
     789              : 
     790         9505 :                 jump_stack.remove_at (jump_stack.size - 1);
     791         9505 :                 jump_stack.remove_at (jump_stack.size - 1);
     792              :         }
     793              : 
     794          334 :         public override void visit_foreach_statement (ForeachStatement stmt) {
     795          167 :                 if (unreachable (stmt)) {
     796              :                         return;
     797              :                 }
     798              : 
     799              :                 // collection
     800          167 :                 current_block.add_node (stmt.collection);
     801          167 :                 handle_errors (stmt.collection);
     802              : 
     803          167 :                 var loop_block = new BasicBlock ();
     804          167 :                 all_basic_blocks.add (loop_block);
     805          167 :                 jump_stack.add (new JumpTarget.continue_target (loop_block));
     806          167 :                 var after_loop_block = new BasicBlock ();
     807          167 :                 all_basic_blocks.add (after_loop_block);
     808          167 :                 jump_stack.add (new JumpTarget.break_target (after_loop_block));
     809              : 
     810              :                 // loop block
     811          167 :                 var last_block = current_block;
     812          167 :                 last_block.connect (loop_block);
     813          334 :                 current_block = loop_block;
     814          167 :                 current_block.add_node (stmt);
     815          167 :                 stmt.body.accept (this);
     816          167 :                 if (current_block != null) {
     817          165 :                         current_block.connect (loop_block);
     818              :                 }
     819              : 
     820              :                 // after loop
     821          167 :                 last_block.connect (after_loop_block);
     822          167 :                 if (current_block != null) {
     823          165 :                         current_block.connect (after_loop_block);
     824              :                 }
     825          334 :                 current_block = after_loop_block;
     826              : 
     827          167 :                 jump_stack.remove_at (jump_stack.size - 1);
     828          167 :                 jump_stack.remove_at (jump_stack.size - 1);
     829              :         }
     830              : 
     831        12844 :         public override void visit_break_statement (BreakStatement stmt) {
     832        12844 :                 if (unreachable (stmt)) {
     833              :                         return;
     834              :                 }
     835              : 
     836        12843 :                 current_block.add_node (stmt);
     837              : 
     838        13017 :                 for (int i = jump_stack.size - 1; i >= 0; i--) {
     839        12929 :                         var jump_target = jump_stack[i];
     840        12929 :                         if (jump_target.is_break_target) {
     841        12842 :                                 current_block.connect (jump_target.basic_block);
     842        12842 :                                 mark_unreachable ();
     843        12842 :                                 return;
     844           87 :                         } else if (jump_target.is_finally_clause) {
     845            0 :                                 current_block.connect (jump_target.basic_block);
     846            0 :                                 current_block = jump_target.last_block;
     847              :                         }
     848              :                 }
     849              : 
     850            1 :                 Report.error (stmt.source_reference, "no enclosing loop or switch statement found");
     851            1 :                 stmt.error = true;
     852              :         }
     853              : 
     854          116 :         public override void visit_continue_statement (ContinueStatement stmt) {
     855          116 :                 if (unreachable (stmt)) {
     856              :                         return;
     857              :                 }
     858              : 
     859          116 :                 current_block.add_node (stmt);
     860              : 
     861          522 :                 for (int i = jump_stack.size - 1; i >= 0; i--) {
     862          318 :                         var jump_target = jump_stack[i];
     863          318 :                         if (jump_target.is_continue_target) {
     864          115 :                                 current_block.connect (jump_target.basic_block);
     865          115 :                                 mark_unreachable ();
     866          115 :                                 return;
     867          203 :                         } else if (jump_target.is_finally_clause) {
     868            0 :                                 current_block.connect (jump_target.basic_block);
     869            0 :                                 current_block = jump_target.last_block;
     870              :                         }
     871              :                 }
     872              : 
     873            1 :                 Report.error (stmt.source_reference, "no enclosing loop found");
     874            1 :                 stmt.error = true;
     875              :         }
     876              : 
     877       109061 :         public override void visit_return_statement (ReturnStatement stmt) {
     878       109061 :                 stmt.accept_children (this);
     879              : 
     880       109061 :                 if (unreachable (stmt)) {
     881              :                         return;
     882              :                 }
     883              : 
     884       109059 :                 current_block.add_node (stmt);
     885              : 
     886       109059 :                 if (stmt.return_expression != null) {
     887       108744 :                         handle_errors (stmt.return_expression);
     888              :                 }
     889              : 
     890       331881 :                 for (int i = jump_stack.size - 1; i >= 0; i--) {
     891       220470 :                         var jump_target = jump_stack[i];
     892       220470 :                         if (jump_target.is_return_target) {
     893       109059 :                                 current_block.connect (jump_target.basic_block);
     894       109059 :                                 mark_unreachable ();
     895       109059 :                                 return;
     896       111411 :                         } else if (jump_target.is_finally_clause) {
     897            4 :                                 current_block.connect (jump_target.basic_block);
     898            8 :                                 current_block = jump_target.last_block;
     899              :                         }
     900              :                 }
     901              : 
     902            0 :                 Report.error (stmt.source_reference, "no enclosing loop found");
     903            0 :                 stmt.error = true;
     904              :         }
     905              : 
     906       479339 :         private void handle_errors (CodeNode node, bool always_fail = false) {
     907       482793 :                 if (node.tree_can_fail) {
     908         3454 :                         var last_block = current_block;
     909              : 
     910              :                         // exceptional control flow
     911         3454 :                         var error_types = new ArrayList<DataType> ();
     912         3454 :                         node.get_error_types (error_types);
     913        10386 :                         foreach (DataType error_data_type in error_types) {
     914         3466 :                                 unowned ErrorType? error_type = error_data_type as ErrorType;
     915         3466 :                                 unowned Class? error_class = error_data_type.type_symbol as Class;
     916         6932 :                                 current_block = last_block;
     917         3466 :                                 unreachable_reported = true;
     918              : 
     919         3722 :                                 for (int i = jump_stack.size - 1; i >= 0; i--) {
     920         3594 :                                         var jump_target = jump_stack[i];
     921         3594 :                                         if (jump_target.is_exit_target) {
     922         1381 :                                                 current_block.connect (jump_target.basic_block);
     923         1381 :                                                 mark_unreachable ();
     924         1381 :                                                 break;
     925         2213 :                                         } else if (jump_target.is_error_target) {
     926         2094 :                                                 if (context.profile == Profile.GOBJECT) {
     927         2094 :                                                         if (jump_target.error_domain == null
     928         2001 :                                                             || (jump_target.error_domain == error_type.error_domain
     929         1998 :                                                                 && (jump_target.error_code == null
     930            7 :                                                                     || jump_target.error_code == error_type.error_code))) {
     931              :                                                                 // error can always be caught by this catch clause
     932              :                                                                 // following catch clauses cannot be reached by this error
     933         2085 :                                                                 current_block.connect (jump_target.basic_block);
     934         2085 :                                                                 mark_unreachable ();
     935         2085 :                                                                 break;
     936            9 :                                                         } else if (error_type.error_domain == null
     937            8 :                                                                    || (error_type.error_domain == jump_target.error_domain
     938            6 :                                                                        && (error_type.error_code == null
     939            1 :                                                                            || error_type.error_code == jump_target.error_code))) {
     940              :                                                                 // error might be caught by this catch clause
     941              :                                                                 // unknown at compile time
     942              :                                                                 // following catch clauses might still be reached by this error
     943            6 :                                                                 current_block.connect (jump_target.basic_block);
     944              :                                                         }
     945            0 :                                                 } else if (jump_target.error_class == null || jump_target.error_class == error_class) {
     946              :                                                         // error can always be caught by this catch clause
     947              :                                                         // following catch clauses cannot be reached by this error
     948            0 :                                                         current_block.connect (jump_target.basic_block);
     949            0 :                                                         mark_unreachable ();
     950            0 :                                                         break;
     951            0 :                                                 } else if (jump_target.error_class.is_subtype_of (error_class)) {
     952              :                                                         // error might be caught by this catch clause
     953              :                                                         // unknown at compile time
     954              :                                                         // following catch clauses might still be reached by this error
     955            0 :                                                         current_block.connect (jump_target.basic_block);
     956              :                                                 }
     957          119 :                                         } else if (jump_target.is_finally_clause) {
     958            9 :                                                 current_block.connect (jump_target.basic_block);
     959           18 :                                                 current_block = jump_target.last_block;
     960              :                                         }
     961              :                                 }
     962              :                         }
     963              : 
     964              :                         // normal control flow
     965         3454 :                         if (!always_fail) {
     966         2433 :                                 current_block = new BasicBlock ();
     967         2433 :                                 all_basic_blocks.add (current_block);
     968         2433 :                                 last_block.connect (current_block);
     969              :                         }
     970              :                 }
     971              :         }
     972              : 
     973           17 :         public override void visit_yield_statement (YieldStatement stmt) {
     974           17 :                 if (unreachable (stmt)) {
     975              :                         return;
     976              :                 }
     977              : 
     978           17 :                 stmt.accept_children (this);
     979              :         }
     980              : 
     981         1021 :         public override void visit_throw_statement (ThrowStatement stmt) {
     982         1021 :                 if (unreachable (stmt)) {
     983              :                         return;
     984              :                 }
     985              : 
     986         1021 :                 current_block.add_node (stmt);
     987         1021 :                 handle_errors (stmt, true);
     988              :         }
     989              : 
     990         4189 :         public override void visit_try_statement (TryStatement stmt) {
     991         2096 :                 if (unreachable (stmt)) {
     992              :                         return;
     993              :                 }
     994              : 
     995         2096 :                 var before_try_block = current_block;
     996         2096 :                 var after_try_block = new BasicBlock ();
     997         2096 :                 all_basic_blocks.add (after_try_block);
     998              : 
     999         2096 :                 BasicBlock finally_block = null;
    1000         2138 :                 if (stmt.finally_body != null) {
    1001           44 :                         finally_block = new BasicBlock ();
    1002           44 :                         all_basic_blocks.add (finally_block);
    1003           88 :                         current_block = finally_block;
    1004              : 
    1005              :                         // trap all forbidden jumps
    1006           44 :                         var invalid_block = new BasicBlock ();
    1007           44 :                         all_basic_blocks.add (invalid_block);
    1008           44 :                         jump_stack.add (new JumpTarget.any_target (invalid_block));
    1009              : 
    1010           44 :                         stmt.finally_body.accept (this);
    1011              : 
    1012           44 :                         jump_stack.remove_at (jump_stack.size - 1);
    1013              : 
    1014           44 :                         if (invalid_block.get_predecessors ().size > 0) {
    1015              :                                 // don't allow finally blocks with e.g. return statements
    1016            2 :                                 Report.error (stmt.finally_body.source_reference, "jump out of finally block not permitted");
    1017            2 :                                 stmt.error = true;
    1018            2 :                                 return;
    1019              :                         }
    1020              : 
    1021           42 :                         if (current_block != null) {
    1022           41 :                                 jump_stack.add (new JumpTarget.finally_clause (finally_block, current_block));
    1023              :                         }
    1024              :                 }
    1025              : 
    1026         2094 :                 int finally_jump_stack_size = jump_stack.size;
    1027              : 
    1028         4188 :                 var catch_clauses = stmt.get_catch_clauses ();
    1029         6232 :                 for (int i = catch_clauses.size - 1; i >= 0; i--) {
    1030         2069 :                         var catch_clause = catch_clauses[i];
    1031         2069 :                         var error_block = new BasicBlock ();
    1032         2069 :                         all_basic_blocks.add (error_block);
    1033              : 
    1034         2069 :                         if (catch_clause.error_type != null && !catch_clause.error) {
    1035         2069 :                                 if (context.profile == Profile.GOBJECT) {
    1036         2069 :                                         unowned ErrorType error_type = (ErrorType) catch_clause.error_type;
    1037         4059 :                                         jump_stack.add (new JumpTarget.error_target (error_block, catch_clause, catch_clause.error_type.type_symbol as ErrorDomain, error_type.error_code, null));
    1038              :                                 } else {
    1039            0 :                                         unowned Class? error_class = catch_clause.error_type.type_symbol as Class;
    1040            0 :                                         jump_stack.add (new JumpTarget.error_target (error_block, catch_clause, null, null, error_class));
    1041              :                                 }
    1042              :                         } else {
    1043            0 :                                 jump_stack.add (new JumpTarget.error_target (error_block, catch_clause, null, null, null));
    1044              :                         }
    1045              :                 }
    1046              : 
    1047         4188 :                 current_block = before_try_block;
    1048              : 
    1049         2094 :                 stmt.body.accept (this);
    1050              : 
    1051         2094 :                 if (current_block != null) {
    1052          128 :                         if (finally_block != null) {
    1053           39 :                                 current_block.connect (finally_block);
    1054           39 :                                 current_block = finally_block;
    1055              :                         }
    1056          128 :                         current_block.connect (after_try_block);
    1057              :                 }
    1058              : 
    1059              :                 // remove catch clauses from jump stack
    1060         2094 :                 List<JumpTarget> catch_stack = new ArrayList<JumpTarget> ();
    1061         6232 :                 for (int i = jump_stack.size - 1; i >= finally_jump_stack_size; i--) {
    1062         2069 :                         var jump_target = jump_stack.remove_at (i);
    1063         2069 :                         catch_stack.add (jump_target);
    1064              :                 }
    1065              : 
    1066         6230 :                 foreach (JumpTarget jump_target in catch_stack) {
    1067              : 
    1068         2089 :                         foreach (JumpTarget prev_target in catch_stack) {
    1069         2079 :                                 if (prev_target == jump_target) {
    1070         2068 :                                         break;
    1071              :                                 }
    1072              : 
    1073           11 :                                 if (context.profile == Profile.GOBJECT) {
    1074           11 :                                         if (prev_target.error_domain == jump_target.error_domain &&
    1075            2 :                                             prev_target.error_code == jump_target.error_code) {
    1076            1 :                                                 Report.error (stmt.source_reference, "double catch clause of same error detected");
    1077            1 :                                                 stmt.error = true;
    1078            1 :                                                 return;
    1079              :                                         }
    1080            0 :                                 } else if (prev_target.error_class == jump_target.error_class) {
    1081            0 :                                         Report.error (stmt.source_reference, "double catch clause of same error detected");
    1082            0 :                                         stmt.error = true;
    1083            0 :                                         return;
    1084              :                                 }
    1085              :                         }
    1086              : 
    1087         2068 :                         if (jump_target.basic_block.get_predecessors ().size == 0) {
    1088              :                                 // unreachable
    1089            3 :                                 Report.warning (jump_target.catch_clause.source_reference, "unreachable catch clause detected");
    1090              :                         } else {
    1091         4130 :                                 current_block = jump_target.basic_block;
    1092         2065 :                                 current_block.add_node (jump_target.catch_clause);
    1093         2065 :                                 jump_target.catch_clause.body.accept (this);
    1094         2065 :                                 if (current_block != null) {
    1095           83 :                                         if (finally_block != null) {
    1096            4 :                                                 current_block.connect (finally_block);
    1097            4 :                                                 current_block = finally_block;
    1098              :                                         }
    1099           83 :                                         current_block.connect (after_try_block);
    1100              :                                 }
    1101              :                         }
    1102              :                 }
    1103              : 
    1104         2093 :                 if (finally_block != null) {
    1105           42 :                         jump_stack.remove_at (jump_stack.size - 1);
    1106              :                 }
    1107              : 
    1108              :                 // after try statement
    1109              :                 // reachable?
    1110         2093 :                 if (after_try_block.get_predecessors ().size > 0) {
    1111          314 :                         current_block = after_try_block;
    1112              :                 } else {
    1113         1936 :                         stmt.after_try_block_reachable = false;
    1114         1936 :                         mark_unreachable ();
    1115              :                 }
    1116              :         }
    1117              : 
    1118           26 :         public override void visit_lock_statement (LockStatement stmt) {
    1119           26 :                 if (unreachable (stmt)) {
    1120              :                         return;
    1121              :                 }
    1122              :         }
    1123              : 
    1124           26 :         public override void visit_unlock_statement (UnlockStatement stmt) {
    1125           26 :                 if (unreachable (stmt)) {
    1126              :                         return;
    1127              :                 }
    1128              :         }
    1129              : 
    1130      1585780 :         public override void visit_expression (Expression expr) {
    1131              :                 // lambda expression is handled separately
    1132      1585780 :                 if (!(expr is LambdaExpression)) {
    1133      1581578 :                         expr.accept_children (this);
    1134              :                 }
    1135              :         }
    1136              : 
    1137       550773 :         private bool unreachable (CodeNode node) {
    1138       550773 :                 if (current_block == null) {
    1139           32 :                         node.unreachable = true;
    1140           32 :                         if (!unreachable_reported) {
    1141           30 :                                 Report.warning (node.source_reference, "unreachable code detected");
    1142           30 :                                 unreachable_reported = true;
    1143              :                         }
    1144           32 :                         return true;
    1145              :                 }
    1146              : 
    1147       550773 :                 return false;
    1148              :         }
    1149              : 
    1150       131865 :         void mark_unreachable () {
    1151       131865 :                 current_block = null;
    1152       131865 :                 unreachable_reported = false;
    1153              :         }
    1154              : }
        

Generated by: LCOV version 2.0-1