]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
build control flow graph, report error for missing return statement in
authorJuerg Billeter <j@bitron.ch>
Wed, 23 Jan 2008 15:26:07 +0000 (15:26 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Wed, 23 Jan 2008 15:26:07 +0000 (15:26 +0000)
2008-01-23  Juerg Billeter  <j@bitron.ch>

* vala/Makefile.am, vala/valabasicblock.vala, vala/valacfgbuilder.vala,
  vala/valadostatement.vala, vala/valaforstatement.vala,
  vala/valaifstatement.vala, vala/valamemorymanager.vala,
  vala/valamethod.vala, vala/valasemanticanalyzer.vala,
  vala/valasymbolresolver.vala, vala/valawhilestatement.vala,
  gobject/valaccodegenerator.vala, compiler/valacompiler.vala: build
  control flow graph, report error for missing return statement in
  non-void methods, and report warning for unreachable code,
  fixes bug 508480

* tests/exceptions.vala: add missing return statement

svn path=/trunk/; revision=894

15 files changed:
ChangeLog
compiler/valacompiler.vala
gobject/valaccodegenerator.vala
tests/exceptions.vala
vala/Makefile.am
vala/valabasicblock.vala [new file with mode: 0644]
vala/valacfgbuilder.vala [new file with mode: 0644]
vala/valadostatement.vala
vala/valaforstatement.vala
vala/valaifstatement.vala
vala/valamemorymanager.vala
vala/valamethod.vala
vala/valasemanticanalyzer.vala
vala/valasymbolresolver.vala
vala/valawhilestatement.vala

index c325d5a3a178330c489dd49cff3712b044f19317..9e625d966082a23a77cb6baa826a271ee909946f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2008-01-23  Jürg Billeter  <j@bitron.ch>
+
+       * vala/Makefile.am, vala/valabasicblock.vala, vala/valacfgbuilder.vala,
+         vala/valadostatement.vala, vala/valaforstatement.vala,
+         vala/valaifstatement.vala, vala/valamemorymanager.vala,
+         vala/valamethod.vala, vala/valasemanticanalyzer.vala,
+         vala/valasymbolresolver.vala, vala/valawhilestatement.vala,
+         gobject/valaccodegenerator.vala, compiler/valacompiler.vala: build
+         control flow graph, report error for missing return statement in
+         non-void methods, and report warning for unreachable code,
+         fixes bug 508480
+
+       * tests/exceptions.vala: add missing return statement
+
 2008-01-23  Jürg Billeter  <j@bitron.ch>
 
        * tests/Makefile.am, tests/testrunner.sh: honor EXEEXT to fix tests
index 039fadeb881f294df8a31446da41f37d2cee15d6..5d1d2406fbdfd3880daf0b41188b0dfe3d626f56 100644 (file)
@@ -269,6 +269,13 @@ class Vala.Compiler : Object {
                        return quit ();
                }
 
+               var cfg_builder = new CFGBuilder ();
+               cfg_builder.build_cfg (context);
+
+               if (Report.get_errors () > 0) {
+                       return quit ();
+               }
+
                var memory_manager = new MemoryManager ();
                memory_manager.analyze (context);
 
index 0edceec62ca030f23e39d4afd8b4e85fbeee39b6..d899b60b8d024fb4cc355bba1d79aab172a8eb35 100644 (file)
@@ -1341,6 +1341,8 @@ public class Vala.CCodeGenerator : CodeGenerator {
        }
 
        public override void visit_if_statement (IfStatement! stmt) {
+               stmt.accept_children (this);
+
                if (stmt.false_statement != null) {
                        stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
                } else {
@@ -1496,18 +1498,24 @@ public class Vala.CCodeGenerator : CodeGenerator {
        }
 
        public override void visit_while_statement (WhileStatement! stmt) {
+               stmt.accept_children (this);
+
                stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
                
                create_temp_decl (stmt, stmt.condition.temp_vars);
        }
 
        public override void visit_do_statement (DoStatement! stmt) {
+               stmt.accept_children (this);
+
                stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
                
                create_temp_decl (stmt, stmt.condition.temp_vars);
        }
 
        public override void visit_for_statement (ForStatement! stmt) {
+               stmt.accept_children (this);
+
                var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
                stmt.ccodenode = cfor;
                
index e9e9f54827bd3f850138c310725a49922bc63c16..1da885f93f1f904cb300f97df078d9fbf3444dc5 100644 (file)
@@ -23,6 +23,8 @@ class Maman.Bar : Object {
                foo ();
 
                stdout.printf (" BAD");
+
+               return 0;
        }
 
        public void good () throws BarError {
index 1ddb7441041e3f16f35c5a682883a3b2f4c1866d..3ad6f35f757b17472e6f3b6b601015fd856077a6 100644 (file)
@@ -24,6 +24,7 @@ libvalacore_la_VALASOURCES = \
        valaattribute.vala \
        valaattributeprocessor.vala \
        valabaseaccess.vala \
+       valabasicblock.vala \
        valabinaryexpression.vala \
        valabindingprovider.vala \
        valablock.vala \
@@ -31,6 +32,7 @@ libvalacore_la_VALASOURCES = \
        valabreakstatement.vala \
        valacastexpression.vala \
        valacatchclause.vala \
+       valacfgbuilder.vala \
        valacharacterliteral.vala \
        valaclass.vala \
        valaclasstype.vala \
diff --git a/vala/valabasicblock.vala b/vala/valabasicblock.vala
new file mode 100644 (file)
index 0000000..bee0171
--- /dev/null
@@ -0,0 +1,65 @@
+/* valabasicblock.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Represents a basic block, i.e. a straight-line piece of code without any
+ * jumps or jump targets.
+ */
+public class Vala.BasicBlock : Object {
+       private Gee.List<CodeNode> nodes = new ArrayList<CodeNode> ();
+
+       private Gee.List<weak BasicBlock> predecessors = new ArrayList<weak BasicBlock> ();
+       private Gee.List<BasicBlock> successors = new ArrayList<BasicBlock> ();
+
+       public BasicBlock () {
+       }
+
+       public BasicBlock.entry () {
+       }
+
+       public BasicBlock.exit () {
+       }
+
+       public void add_node (CodeNode node) {
+               nodes.add (node);
+       }
+
+       public void connect (BasicBlock target) {
+               if (!successors.contains (target)) {
+                       successors.add (target);
+               }
+               if (!target.predecessors.contains (this)) {
+                       target.predecessors.add (this);
+               }
+       }
+
+       public Gee.List<weak BasicBlock> get_predecessors () {
+               return new ReadOnlyList<weak BasicBlock> (predecessors);
+       }
+
+       public Gee.List<weak BasicBlock> get_successors () {
+               return new ReadOnlyList<weak BasicBlock> (successors);
+       }
+}
diff --git a/vala/valacfgbuilder.vala b/vala/valacfgbuilder.vala
new file mode 100644 (file)
index 0000000..b6a882b
--- /dev/null
@@ -0,0 +1,395 @@
+/* valacfgbuilder.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Code visitor building the control flow graph.
+ */
+public class Vala.CFGBuilder : CodeVisitor {
+       private CodeContext context;
+       private BasicBlock current_block;
+       private bool unreachable_reported;
+       private Method current_method;
+       private Gee.List<BasicBlock> breakable_stack = new ArrayList<BasicBlock> ();
+       private Gee.List<BasicBlock> continuable_stack = new ArrayList<BasicBlock> ();
+
+       public CFGBuilder () {
+       }
+
+       /**
+        * Build control flow graph in the specified context.
+        *
+        * @param context a code context
+        */
+       public void build_cfg (CodeContext! context) {
+               this.context = context;
+
+               /* we're only interested in non-pkg source files */
+               var source_files = context.get_source_files ();
+               foreach (SourceFile file in source_files) {
+                       if (!file.pkg) {
+                               file.accept (this);
+                       }
+               }
+       }
+
+       public override void visit_source_file (SourceFile! source_file) {
+               source_file.accept_children (this);
+       }
+
+       public override void visit_class (Class! cl) {
+               cl.accept_children (this);
+       }
+
+       public override void visit_struct (Struct! st) {
+               st.accept_children (this);
+       }
+
+       public override void visit_interface (Interface! iface) {
+               iface.accept_children (this);
+       }
+
+       public override void visit_enum (Enum! en) {
+               en.accept_children (this);
+       }
+
+       public override void visit_method (Method! m) {
+               if (m.body == null) {
+                       return;
+               }
+
+               var old_method = current_method;
+               current_method = m;
+
+               m.entry_block = new BasicBlock.entry ();
+               m.exit_block = new BasicBlock.exit ();
+
+               current_block = new BasicBlock ();
+               m.entry_block.connect (current_block);
+
+               m.accept_children (this);
+
+               if (current_block != null) {
+                       // end of method body reachable
+
+                       if (!(m.return_type is VoidType)) {
+                               Report.error (m.source_reference, "missing return statement at end of method body");
+                               m.error = true;
+                       }
+
+                       current_block.connect (m.exit_block);
+               }
+
+               current_method = old_method;
+       }
+
+       public override void visit_block (Block! b) {
+               b.accept_children (this);
+       }
+
+       public override void visit_declaration_statement (DeclarationStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+       }
+
+       public override void visit_expression_statement (ExpressionStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+       }
+
+       public override void visit_if_statement (IfStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               // condition
+               current_block.add_node (stmt.condition);
+
+               // true block
+               var last_block = current_block;
+               current_block = new BasicBlock ();
+               last_block.connect (current_block);
+               stmt.true_statement.accept (this);
+
+               // false block
+               var last_true_block = current_block;
+               current_block = new BasicBlock ();
+               last_block.connect (current_block);
+               if (stmt.false_statement != null) {
+                       stmt.false_statement.accept (this);
+               }
+
+               // after if/else
+               var last_false_block = current_block;
+               // reachable?
+               if (last_true_block != null || last_false_block != null) {
+                       current_block = new BasicBlock ();
+                       if (last_true_block != null) {
+                               last_true_block.connect (current_block);
+                       }
+                       if (last_false_block != null) {
+                               last_false_block.connect (current_block);
+                       }
+               }
+       }
+
+       public override void visit_while_statement (WhileStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               var condition_block = new BasicBlock ();
+               continuable_stack.add (condition_block);
+               var after_loop_block = new BasicBlock ();
+               breakable_stack.add (after_loop_block);
+
+               // condition
+               var last_block = current_block;
+               last_block.connect (condition_block);
+               condition_block.add_node (stmt.condition);
+
+               // loop block
+               current_block = new BasicBlock ();
+               condition_block.connect (current_block);
+               stmt.body.accept (this);
+               // end of loop block reachable?
+               if (current_block != null) {
+                       current_block.connect (condition_block);
+               }
+
+               // after loop
+               condition_block.connect (after_loop_block);
+               current_block = after_loop_block;
+
+               continuable_stack.remove_at (continuable_stack.size - 1);
+               breakable_stack.remove_at (breakable_stack.size - 1);
+       }
+
+       public override void visit_do_statement (DoStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               var condition_block = new BasicBlock ();
+               continuable_stack.add (condition_block);
+               var after_loop_block = new BasicBlock ();
+               breakable_stack.add (after_loop_block);
+
+               // loop block
+               var last_block = current_block;
+               var loop_block = new BasicBlock ();
+               last_block.connect (loop_block);
+               current_block = loop_block;
+               stmt.body.accept (this);
+
+               // condition
+               // reachable?
+               if (current_block != null || condition_block.get_predecessors ().size > 0) {
+                       if (current_block != null) {
+                               last_block = current_block;
+                               last_block.connect (condition_block);
+                       }
+                       condition_block.add_node (stmt.condition);
+                       condition_block.connect (loop_block);
+                       current_block = condition_block;
+               }
+
+               // after loop
+               // reachable?
+               if (current_block != null || after_loop_block.get_predecessors ().size > 0) {
+                       if (current_block != null) {
+                               last_block = current_block;
+                               last_block.connect (after_loop_block);
+                       }
+                       current_block = after_loop_block;
+               }
+
+               continuable_stack.remove_at (continuable_stack.size - 1);
+               breakable_stack.remove_at (breakable_stack.size - 1);
+       }
+
+       public override void visit_for_statement (ForStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               // initializer
+               foreach (Expression init_expr in stmt.get_initializer ()) {
+                       current_block.add_node (init_expr);
+               }
+
+               var iterator_block = new BasicBlock ();
+               continuable_stack.add (iterator_block);
+               var after_loop_block = new BasicBlock ();
+               breakable_stack.add (after_loop_block);
+
+               // condition
+               var condition_block = new BasicBlock ();
+               current_block.connect (condition_block);
+               condition_block.add_node (stmt.condition);
+
+               // loop block
+               current_block = new BasicBlock ();
+               condition_block.connect (current_block);
+               stmt.body.accept (this);
+
+               // iterator
+               // reachable?
+               if (current_block != null || iterator_block.get_predecessors ().size > 0) {
+                       if (current_block != null) {
+                               current_block.connect (iterator_block);
+                       }
+                       foreach (Expression it_expr in stmt.get_iterator ()) {
+                               iterator_block.add_node (it_expr);
+                       }
+                       iterator_block.connect (condition_block);
+               }
+
+               // after loop
+               condition_block.connect (after_loop_block);
+               current_block = after_loop_block;
+
+               continuable_stack.remove_at (continuable_stack.size - 1);
+               breakable_stack.remove_at (breakable_stack.size - 1);
+       }
+
+       public override void visit_foreach_statement (ForeachStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               var loop_block = new BasicBlock ();
+               continuable_stack.add (loop_block);
+               var after_loop_block = new BasicBlock ();
+               breakable_stack.add (after_loop_block);
+
+               // loop block
+               var last_block = current_block;
+               last_block.connect (loop_block);
+               current_block = loop_block;
+               stmt.body.accept (this);
+               if (current_block != null) {
+                       current_block.connect (loop_block);
+               }
+
+               // after loop
+               last_block.connect (after_loop_block);
+               if (current_block != null) {
+                       current_block.connect (after_loop_block);
+               }
+               current_block = after_loop_block;
+
+               continuable_stack.remove_at (continuable_stack.size - 1);
+               breakable_stack.remove_at (breakable_stack.size - 1);
+       }
+
+       public override void visit_break_statement (BreakStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+               current_block.connect (top_breakable ());
+               current_block = null;
+               unreachable_reported = false;
+       }
+
+       public override void visit_continue_statement (ContinueStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+               current_block.connect (top_continuable ());
+               current_block = null;
+               unreachable_reported = false;
+       }
+
+       public override void visit_return_statement (ReturnStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+               current_block.connect (current_method.exit_block);
+               current_block = null;
+               unreachable_reported = false;
+       }
+
+       public override void visit_throw_statement (ThrowStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               current_block.add_node (stmt);
+               // TODO connect to catch blocks instead of exit block if appropriate
+               current_block.connect (current_method.exit_block);
+               current_block = null;
+               unreachable_reported = false;
+       }
+
+       public override void visit_try_statement (TryStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               stmt.body.accept (this);
+
+               // TODO exceptional control flow
+       }
+
+       public override void visit_lock_statement (LockStatement! stmt) {
+               if (unreachable (stmt)) {
+                       return;
+               }
+
+               stmt.body.accept (this);
+       }
+
+       private bool unreachable (CodeNode node) {
+               if (current_block == null) {
+                       if (!unreachable_reported) {
+                               Report.warning (node.source_reference, "unreachable code detected");
+                               unreachable_reported = true;
+                       }
+                       return true;
+               }
+
+               return false;
+       }
+
+       private BasicBlock top_breakable () {
+               return breakable_stack.get (breakable_stack.size - 1);
+       }
+
+       private BasicBlock top_continuable () {
+               return continuable_stack.get (continuable_stack.size - 1);
+       }
+}
index 3d237959411cf19ad0342dbc10c0e9411782a877..e5fdd22c648e7464e3cc12f15eadd1e47f40717f 100644 (file)
@@ -1,6 +1,6 @@
 /* valadostatement.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -65,15 +65,17 @@ public class Vala.DoStatement : CodeNode, Statement {
         */
        public DoStatement (construct Block! body, construct Expression! condition, construct SourceReference source_reference = null) {
        }
-       
+
        public override void accept (CodeVisitor! visitor) {
+               visitor.visit_do_statement (this);
+       }
+
+       public override void accept_children (CodeVisitor! visitor) {
                body.accept (visitor);
 
                condition.accept (visitor);
                
                visitor.visit_end_full_expression (condition);
-
-               visitor.visit_do_statement (this);
        }
 
        public override void replace_expression (Expression! old_node, Expression! new_node) {
index 7d6327bdef2cb1f8a948416cc914117cd77b2331..68676e0d12bd42bde312abbc5623991966511724 100644 (file)
@@ -1,6 +1,6 @@
 /* valaforstatement.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -109,6 +109,10 @@ public class Vala.ForStatement : CodeNode, Statement {
        }
        
        public override void accept (CodeVisitor! visitor) {
+               visitor.visit_for_statement (this);
+       }
+       
+       public override void accept_children (CodeVisitor! visitor) {
                foreach (Expression init_expr in initializer) {
                        init_expr.accept (visitor);
                        visitor.visit_end_full_expression (init_expr);
@@ -124,8 +128,6 @@ public class Vala.ForStatement : CodeNode, Statement {
                }
                
                body.accept (visitor);
-
-               visitor.visit_for_statement (this);
        }
 
        public override void replace_expression (Expression! old_node, Expression! new_node) {
index b12916a9c9f88e63ec0e998d20dd16c9761a0e8b..237a00edd247ff10c1878dda0d6d640dce8c5dc9 100644 (file)
@@ -1,6 +1,6 @@
 /* valaifstatement.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -67,6 +67,10 @@ public class Vala.IfStatement : CodeNode, Statement {
        }
        
        public override void accept (CodeVisitor! visitor) {
+               visitor.visit_if_statement (this);
+       }
+
+       public override void accept_children (CodeVisitor! visitor) {
                condition.accept (visitor);
                
                visitor.visit_end_full_expression (condition);
@@ -75,8 +79,6 @@ public class Vala.IfStatement : CodeNode, Statement {
                if (false_statement != null) {
                        false_statement.accept (visitor);
                }
-
-               visitor.visit_if_statement (this);
        }
 
        public override void replace_expression (Expression! old_node, Expression! new_node) {
index 9c7e79736006308b79f745556a0d53303df1a7bd..375027a4d62c55c13a730e74e75bb2237988434a 100644 (file)
@@ -149,10 +149,26 @@ public class Vala.MemoryManager : CodeVisitor {
                visit_possibly_leaked_expression (stmt.expression);
        }
 
+       public override void visit_if_statement (IfStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
        public override void visit_switch_section (SwitchSection! section) {
                section.accept_children (this);
        }
 
+       public override void visit_while_statement (WhileStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_do_statement (DoStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_for_statement (ForStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
        public override void visit_foreach_statement (ForeachStatement! stmt) {
                stmt.accept_children (this);
        }
index 59cb0701640e46415f646ec7451fd7a4e20a87ae..d94c335c06d4f24b10da178e163a7e22e4836bd6 100644 (file)
@@ -42,7 +42,11 @@ public class Vala.Method : Member {
        }
        
        public Block body { get; set; }
-       
+
+       public BasicBlock entry_block { get; set; }
+
+       public BasicBlock exit_block { get; set; }
+
        /**
         * Specifies whether this method may only be called with an instance of
         * the contained type.
index 4288c8cb1228ec3c235b5a935d5d14a531bb5ca4..b4b1525f9042dd06dae982ffb1c1a4dd495d7dcb 100644 (file)
@@ -858,6 +858,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        }
 
        public override void visit_if_statement (IfStatement! stmt) {
+               stmt.accept_children (this);
+
                if (stmt.condition.error) {
                        /* if there was an error in the condition, skip this check */
                        stmt.error = true;
@@ -891,6 +893,24 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        }
 
        public override void visit_while_statement (WhileStatement! stmt) {
+               stmt.accept_children (this);
+
+               if (stmt.condition.error) {
+                       /* if there was an error in the condition, skip this check */
+                       stmt.error = true;
+                       return;
+               }
+
+               if (!stmt.condition.static_type.compatible (bool_type)) {
+                       stmt.error = true;
+                       Report.error (stmt.condition.source_reference, "Condition must be boolean");
+                       return;
+               }
+       }
+
+       public override void visit_do_statement (DoStatement! stmt) {
+               stmt.accept_children (this);
+
                if (stmt.condition.error) {
                        /* if there was an error in the condition, skip this check */
                        stmt.error = true;
@@ -905,6 +925,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        }
 
        public override void visit_for_statement (ForStatement! stmt) {
+               stmt.accept_children (this);
+
                if (stmt.condition.error) {
                        /* if there was an error in the condition, skip this check */
                        stmt.error = true;
index 0872f3df1fae0c8d1a7f18e1eddfd8fa22dc3ca2..7ae1adac10624f9ca20e527f60a8a6ab8f5a3bf8 100644 (file)
@@ -322,10 +322,26 @@ public class Vala.SymbolResolver : CodeVisitor {
                list.accept_children (this);
        }
 
+       public override void visit_if_statement (IfStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
        public override void visit_switch_section (SwitchSection! section) {
                section.accept_children (this);
        }
 
+       public override void visit_while_statement (WhileStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_do_statement (DoStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_for_statement (ForStatement! stmt) {
+               stmt.accept_children (this);
+       }
+
        public override void visit_foreach_statement (ForeachStatement! stmt) {
                stmt.accept_children (this);
        }
index a1afdce705b8c8d685d9d02a6e7192ca0409524c..77d16e0fbd679f1812ce6e8a2cef9f97701f1ca2 100644 (file)
@@ -1,6 +1,6 @@
 /* valawhilestatement.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -67,13 +67,15 @@ public class Vala.WhileStatement : CodeNode, Statement {
        }
        
        public override void accept (CodeVisitor! visitor) {
+               visitor.visit_while_statement (this);
+       }
+
+       public override void accept_children (CodeVisitor! visitor) {
                condition.accept (visitor);
                
                visitor.visit_end_full_expression (condition);
 
                body.accept (visitor);
-
-               visitor.visit_while_statement (this);
        }
 
        public override void replace_expression (Expression! old_node, Expression! new_node) {