[vala/wip/transform: 82/179] Make the semantic analyzer be stateless



commit bfe681d0b2caaa750abe43532da33d03744c9519
Author: Luca Bruno <lucabru src gnome org>
Date:   Sat Aug 6 10:38:59 2011 +0200

    Make the semantic analyzer be stateless

 vala/valaassignment.vala               |   27 ++--
 vala/valabaseaccess.vala               |   19 ++-
 vala/valabinaryexpression.vala         |   12 +-
 vala/valablock.vala                    |   18 +--
 vala/valacatchclause.vala              |    7 +-
 vala/valaclass.vala                    |  111 +++++++++-----
 vala/valaconditionalexpression.vala    |    6 +-
 vala/valaconstant.vala                 |   16 +--
 vala/valaconstructor.vala              |    7 +-
 vala/valacreationmethod.vala           |   27 +----
 vala/valadelegate.vala                 |   22 +--
 vala/valadestructor.vala               |    5 -
 vala/valaenum.vala                     |   15 +--
 vala/valaerrorcode.vala                |   14 ++-
 vala/valafield.vala                    |   15 +--
 vala/valaforeachstatement.vala         |   20 +--
 vala/valainterface.vala                |   31 ++---
 vala/valalambdaexpression.vala         |   20 ++--
 vala/valalocalvariable.vala            |   10 +-
 vala/valalockstatement.vala            |   27 +++-
 vala/valamemberaccess.vala             |   51 +++----
 vala/valamethod.vala                   |   13 +--
 vala/valamethodcall.vala               |   13 +-
 vala/valaobjectcreationexpression.vala |   22 ++-
 vala/valaparameter.vala                |   21 +--
 vala/valaproperty.vala                 |   31 ++---
 vala/valapropertyaccessor.vala         |   12 +-
 vala/valareturnstatement.vala          |   24 ++--
 vala/valasemanticanalyzer.vala         |  254 ++++++++++++++------------------
 vala/valastruct.vala                   |   33 ++---
 vala/valasubroutine.vala               |    1 -
 vala/valaswitchlabel.vala              |   22 ++-
 vala/valaswitchsection.vala            |   24 +--
 vala/valaunlockstatement.vala          |    2 +-
 34 files changed, 424 insertions(+), 528 deletions(-)
---
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index b3e07b4..d458d19 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -37,12 +37,12 @@ public class Vala.Assignment : Expression {
                        _left.parent_node = this;
                }
        }
-
+       
        /**
         * Assignment operator.
         */
        public AssignmentOperator operator { get; set; }
-
+       
        /**
         * Right hand side of the assignment.
         */
@@ -53,10 +53,10 @@ public class Vala.Assignment : Expression {
                        _right.parent_node = this;
                }
        }
-
+       
        private Expression _left;
        private Expression _right;
-
+       
        /**
         * Creates a new assignment.
         *
@@ -72,7 +72,7 @@ public class Vala.Assignment : Expression {
                this.source_reference = source_reference;
                this.left = left;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_assignment (this);
 
@@ -108,20 +108,22 @@ public class Vala.Assignment : Expression {
 
                checked = true;
 
+               var insert_block = context.analyzer.get_insert_block (this);
+
                if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is 
ExpressionStatement) {
                        var tuple = (Tuple) left;
 
                        var local = new LocalVariable (null, get_temp_name (), right, right.source_reference);
                        var decl = new DeclarationStatement (local, source_reference);
                        decl.check (context);
-                       insert_statement (context.analyzer.insert_block, decl);
+                       insert_statement (insert_block, decl);
 
                        int i = 0;
                        ExpressionStatement stmt = null;
                        foreach (var expr in tuple.get_expressions ()) {
                                if (stmt != null) {
                                        stmt.check (context);
-                                       insert_statement (context.analyzer.insert_block, stmt);
+                                       insert_statement (insert_block, stmt);
                                }
 
                                var temp_access = new MemberAccess.simple (local.name, 
right.source_reference);
@@ -156,7 +158,7 @@ public class Vala.Assignment : Expression {
                        }
 
                        if ((!(ma.symbol_reference is Signal || ma.symbol_reference is DynamicProperty) && 
ma.value_type == null) ||
-                           (ma.inner == null && ma.member_name == "this" && 
context.analyzer.is_in_instance_method ())) {
+                           (ma.inner == null && ma.member_name == "this" && 
context.analyzer.is_in_instance_method (this))) {
                                error = true;
                                Report.error (source_reference, "unsupported lvalue in assignment");
                                return false;
@@ -308,15 +310,16 @@ public class Vala.Assignment : Expression {
                                        left.value_type = dynamic_prop.property_type.copy ();
                                }
 
+                               var current_method = context.analyzer.get_current_method (this);
                                if (prop.set_accessor == null
-                                   || (!prop.set_accessor.writable && !(context.analyzer.find_current_method 
() is CreationMethod || context.analyzer.is_in_constructor ()))) {
+                                   || (!prop.set_accessor.writable && !(current_method is CreationMethod || 
context.analyzer.is_in_constructor (this)))) {
                                        ma.error = true;
                                        Report.error (ma.source_reference, "Property `%s' is 
read-only".printf (prop.get_full_name ()));
                                        return false;
                                } else if (!context.deprecated
                                           && !prop.set_accessor.writable
-                                          && context.analyzer.find_current_method () is CreationMethod) {
-                                       if (ma.inner.symbol_reference != context.analyzer.find_current_method 
().this_parameter) {
+                                          && current_method is CreationMethod) {
+                                       if (ma.inner.symbol_reference != current_method.this_parameter) {
                                                // trying to set construct-only property in creation method 
for foreign instance
                                                Report.error (ma.source_reference, "Property `%s' is 
read-only".printf (prop.get_full_name ()));
                                                return false;
@@ -563,7 +566,7 @@ public class Vala.Assignment : Expression {
                right.get_used_variables (collection);
        }
 }
-
+       
 public enum Vala.AssignmentOperator {
        NONE,
        SIMPLE,
diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala
index 7631f9e..4d7caed 100644
--- a/vala/valabaseaccess.vala
+++ b/vala/valabaseaccess.vala
@@ -34,7 +34,7 @@ public class Vala.BaseAccess : Expression {
        public BaseAccess (SourceReference? source = null) {
                source_reference = source;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_base_access (this);
 
@@ -56,29 +56,32 @@ public class Vala.BaseAccess : Expression {
 
                checked = true;
 
-               if (!context.analyzer.is_in_instance_method ()) {
+               if (!context.analyzer.is_in_instance_method (this)) {
                        error = true;
                        Report.error (source_reference, "Base access invalid outside of instance methods");
                        return false;
                }
 
-               if (context.analyzer.current_class == null) {
-                       if (context.analyzer.current_struct == null) {
+               var current_class = context.analyzer.get_current_class (this);
+               var current_struct = context.analyzer.get_current_struct (this);
+
+               if (current_class == null) {
+                       if (current_struct == null) {
                                error = true;
                                Report.error (source_reference, "Base access invalid outside of class and 
struct");
                                return false;
-                       } else if (context.analyzer.current_struct.base_type == null) {
+                       } else if (current_struct.base_type == null) {
                                error = true;
                                Report.error (source_reference, "Base access invalid without base type");
                                return false;
                        }
-                       value_type = context.analyzer.current_struct.base_type;
-               } else if (context.analyzer.current_class.base_class == null) {
+                       value_type = current_struct.base_type;
+               } else if (current_class.base_class == null) {
                        error = true;
                        Report.error (source_reference, "Base access invalid without base class");
                        return false;
                } else {
-                       foreach (var base_type in context.analyzer.current_class.get_base_types ()) {
+                       foreach (var base_type in current_class.get_base_types ()) {
                                if (base_type.data_type is Class) {
                                        value_type = base_type.copy ();
                                        value_type.value_owned = false;
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
index 3557173..99a54aa 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -161,9 +161,11 @@ public class Vala.BinaryExpression : Expression {
 
                checked = true;
 
+               var insert_block = context.analyzer.get_insert_block (this);
+
                // some expressions are not in a block,
                // for example, expressions in method contracts
-               if (context.analyzer.current_symbol is Block
+               if (context.analyzer.get_current_symbol (this) is Block
                    && (operator == BinaryOperator.AND || operator == BinaryOperator.OR)) {
                        // convert conditional expression into if statement
                        // required for flow analysis and exception handling
@@ -188,8 +190,8 @@ public class Vala.BinaryExpression : Expression {
 
                        var if_stmt = new IfStatement (left, true_block, false_block, source_reference);
 
-                       insert_statement (context.analyzer.insert_block, decl);
-                       insert_statement (context.analyzer.insert_block, if_stmt);
+                       insert_statement (insert_block, decl);
+                       insert_statement (insert_block, if_stmt);
 
                        decl.check (context);
 
@@ -263,8 +265,8 @@ public class Vala.BinaryExpression : Expression {
 
                        var if_stmt = new IfStatement (cond, true_block, null, source_reference);
 
-                       insert_statement (context.analyzer.insert_block, decl);
-                       insert_statement (context.analyzer.insert_block, if_stmt);
+                       insert_statement (insert_block, decl);
+                       insert_statement (insert_block, if_stmt);
 
                        if (!decl.check (context)) {
                                error = true;
diff --git a/vala/valablock.vala b/vala/valablock.vala
index 372e709..6388a57 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -37,7 +37,7 @@ public class Vala.Block : Symbol, Statement {
        private List<Statement> statement_list = new ArrayList<Statement> ();
        private List<LocalVariable> local_variables = new ArrayList<LocalVariable> ();
        private List<Constant> local_constants = new ArrayList<Constant> ();
-
+       
        /**
         * Creates a new block.
         *
@@ -46,7 +46,7 @@ public class Vala.Block : Symbol, Statement {
        public Block (SourceReference? source_reference) {
                base (null, source_reference);
        }
-
+       
        /**
         * Append a statement to this block.
         *
@@ -81,7 +81,7 @@ public class Vala.Block : Symbol, Statement {
                }
                return list;
        }
-
+       
        /**
         * Add a local variable to this block.
         *
@@ -97,10 +97,12 @@ public class Vala.Block : Symbol, Statement {
                        parent_block = parent_block.parent_symbol;
                }
                local_variables.add (local);
+               scope.add (local.name, local);
        }
 
        public void remove_local_variable (LocalVariable local) {
                local_variables.remove (local);
+               scope.remove (local.name);
        }
 
        /**
@@ -142,12 +144,7 @@ public class Vala.Block : Symbol, Statement {
 
                checked = true;
 
-               owner = context.analyzer.current_symbol.scope;
-
-               var old_symbol = context.analyzer.current_symbol;
-               var old_insert_block = context.analyzer.insert_block;
-               context.analyzer.current_symbol = this;
-               context.analyzer.insert_block = this;
+               owner = context.analyzer.get_current_symbol (parent_node).scope;
 
                for (int i = 0; i < statement_list.size; i++) {
                        statement_list[i].check (context);
@@ -166,9 +163,6 @@ public class Vala.Block : Symbol, Statement {
                        add_error_types (stmt.get_error_types ());
                }
 
-               context.analyzer.current_symbol = old_symbol;
-               context.analyzer.insert_block = old_insert_block;
-
                return !error;
        }
 
diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala
index 93996a9..e3efd58 100644
--- a/vala/valacatchclause.vala
+++ b/vala/valacatchclause.vala
@@ -37,12 +37,12 @@ public class Vala.CatchClause : CodeNode {
                        }
                }
        }
-
+       
        /**
         * Specifies the error variable name.
         */
        public string? variable_name { get; set; }
-
+       
        /**
         * Specifies the error handler body.
         */
@@ -53,7 +53,7 @@ public class Vala.CatchClause : CodeNode {
                        _body.parent_node = this;
                }
        }
-
+       
        /**
         * Specifies the declarator for the generated error variable.
         */
@@ -125,7 +125,6 @@ public class Vala.CatchClause : CodeNode {
                        if (variable_name != null) {
                                error_variable = new LocalVariable (error_type.copy (), variable_name);
 
-                               body.scope.add (variable_name, error_variable);
                                body.add_local_variable (error_variable);
 
                                error_variable.checked = true;
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index b0de0f5..0ad9332 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -30,7 +30,7 @@ public class Vala.Class : ObjectTypeSymbol {
         * Specifies the base class.
         */
        public Class base_class { get; set; }
-
+       
        /**
         * Specifies whether this class is abstract. Abstract classes may not be
         * instantiated.
@@ -89,7 +89,7 @@ public class Vala.Class : ObjectTypeSymbol {
         * Specifies whether this class has private fields.
         */
        public bool has_private_fields { get; set; }
-
+       
        /**
         * Specifies whether this class has class fields.
         */
@@ -104,21 +104,45 @@ public class Vala.Class : ObjectTypeSymbol {
         * Specifies the default construction method.
         */
        public CreationMethod default_construction_method { get; set; }
-
+       
        /**
         * Specifies the instance constructor.
         */
-       public Constructor constructor { get; set; }
+       public Constructor constructor {
+               get { return _constructor; }
+               set {
+                       _constructor = value;
+                       if (_constructor != null) {
+                               _constructor.owner = scope;
+                       }
+               }
+       }
 
        /**
         * Specifies the class constructor.
         */
-       public Constructor class_constructor { get; set; }
+       public Constructor class_constructor {
+               get { return _class_constructor; }
+               set {
+                       _class_constructor = value;
+                       if (_class_constructor != null) {
+                               _class_constructor.owner = scope;
+                       }
+               }
+       }
 
        /**
         * Specifies the static class constructor.
         */
-       public Constructor static_constructor { get; set; }
+       public Constructor static_constructor {
+               get { return _static_constructor; }
+               set {
+                       _static_constructor = value;
+                       if (_static_constructor != null) {
+                               _static_constructor.owner = scope;
+                       }
+               }
+       }
 
        /**
         * Specifies the instance destructor.
@@ -128,6 +152,7 @@ public class Vala.Class : ObjectTypeSymbol {
                set {
                        _destructor = value;
                        if (_destructor != null) {
+                               _destructor.owner = scope;
                                if (_destructor.this_parameter != null) {
                                        _destructor.scope.remove (_destructor.this_parameter.name);
                                }
@@ -140,12 +165,28 @@ public class Vala.Class : ObjectTypeSymbol {
        /**
         * Specifies the class destructor.
         */
-       public Destructor? static_destructor { get; set; }
-
+       public Destructor? static_destructor {
+               get { return _static_destructor; }
+               set {
+                       _static_destructor = value;
+                       if (_static_destructor != null) {
+                               _static_destructor.owner = scope;
+                       }
+               }
+       }
+       
        /**
         * Specifies the class destructor.
         */
-       public Destructor? class_destructor { get; set; }
+       public Destructor? class_destructor {
+               get { return _class_destructor; }
+               set {
+                       _class_destructor = value;
+                       if (_class_destructor != null) {
+                               _class_destructor.owner = scope;
+                       }
+               }
+       }
 
        /**
         * Specifies whether this class denotes an error base.
@@ -156,7 +197,12 @@ public class Vala.Class : ObjectTypeSymbol {
                }
        }
 
+       Constructor _constructor;
+       Constructor _class_constructor;
+       Constructor _static_constructor;
        Destructor? _destructor;
+       Destructor? _class_destructor;
+       Destructor? _static_destructor;
 
        /**
         * Creates a new class.
@@ -204,7 +250,7 @@ public class Vala.Class : ObjectTypeSymbol {
                        has_class_private_fields = true;
                }
        }
-
+       
        /**
         * Adds the specified method as a member to this class.
         *
@@ -263,7 +309,7 @@ public class Vala.Class : ObjectTypeSymbol {
                        add_field (prop.field);
                }
        }
-
+       
        public override void add_constructor (Constructor c) {
                if (c.binding == MemberBinding.INSTANCE) {
                        if (constructor != null) {
@@ -323,23 +369,23 @@ public class Vala.Class : ObjectTypeSymbol {
                foreach (Field f in get_fields ()) {
                        f.accept (visitor);
                }
-
+               
                foreach (Constant c in get_constants ()) {
                        c.accept (visitor);
                }
-
+               
                foreach (Method m in get_methods ()) {
                        m.accept (visitor);
                }
-
+               
                foreach (Property prop in get_properties ()) {
                        prop.accept (visitor);
                }
-
+               
                foreach (Signal sig in get_signals ()) {
                        sig.accept (visitor);
                }
-
+               
                if (constructor != null) {
                        constructor.accept (visitor);
                }
@@ -363,11 +409,11 @@ public class Vala.Class : ObjectTypeSymbol {
                if (class_destructor != null) {
                        class_destructor.accept (visitor);
                }
-
+               
                foreach (Class cl in get_classes ()) {
                        cl.accept (visitor);
                }
-
+               
                foreach (Struct st in get_structs ()) {
                        st.accept (visitor);
                }
@@ -398,7 +444,7 @@ public class Vala.Class : ObjectTypeSymbol {
                                return true;
                        }
                }
-
+               
                return false;
        }
 
@@ -453,14 +499,6 @@ public class Vala.Class : ObjectTypeSymbol {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                foreach (DataType base_type_reference in get_base_types ()) {
                        if (!base_type_reference.check (context)) {
                                error = true;
@@ -509,15 +547,15 @@ public class Vala.Class : ObjectTypeSymbol {
                foreach (Field f in get_fields ()) {
                        f.check (context);
                }
-
+               
                foreach (Constant c in get_constants ()) {
                        c.check (context);
                }
-
+               
                foreach (Method m in get_methods ()) {
                        m.check (context);
                }
-
+               
                foreach (Property prop in get_properties ()) {
                        if (prop.get_attribute ("NoAccessorMethod") != null && !is_subtype_of 
(context.analyzer.object_type)) {
                                error = true;
@@ -526,11 +564,11 @@ public class Vala.Class : ObjectTypeSymbol {
                        }
                        prop.check (context);
                }
-
+               
                foreach (Signal sig in get_signals ()) {
                        sig.check (context);
                }
-
+               
                if (constructor != null) {
                        constructor.check (context);
                }
@@ -550,15 +588,15 @@ public class Vala.Class : ObjectTypeSymbol {
                if (static_destructor != null) {
                        static_destructor.check (context);
                }
-
+               
                if (class_destructor != null) {
                        class_destructor.check (context);
                }
-
+               
                foreach (Class cl in get_classes ()) {
                        cl.check (context);
                }
-
+               
                foreach (Struct st in get_structs ()) {
                        st.check (context);
                }
@@ -715,9 +753,6 @@ public class Vala.Class : ObjectTypeSymbol {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala
index daf8b7a..4a3d139 100644
--- a/vala/valaconditionalexpression.vala
+++ b/vala/valaconditionalexpression.vala
@@ -111,7 +111,7 @@ public class Vala.ConditionalExpression : Expression {
 
                checked = true;
 
-               if (!(context.analyzer.current_symbol is Block)) {
+               if (!(context.analyzer.get_current_symbol (this) is Block)) {
                        Report.error (source_reference, "Conditional expressions may only be used in blocks");
                        error = true;
                        return false;
@@ -140,8 +140,8 @@ public class Vala.ConditionalExpression : Expression {
 
                var if_stmt = new IfStatement (condition, true_block, false_block, source_reference);
 
-               insert_statement (context.analyzer.insert_block, decl);
-               insert_statement (context.analyzer.insert_block, if_stmt);
+               insert_statement (context.analyzer.get_insert_block (this), decl);
+               insert_statement (context.analyzer.get_insert_block (this), if_stmt);
 
                if (!if_stmt.check (context) || true_expression.error || false_expression.error) {
                        error = true;
diff --git a/vala/valaconstant.vala b/vala/valaconstant.vala
index e50951b..75a21a8 100644
--- a/vala/valaconstant.vala
+++ b/vala/valaconstant.vala
@@ -88,7 +88,7 @@ public class Vala.Constant : Symbol, Lockable {
        public bool get_lock_used () {
                return lock_used;
        }
-
+       
        public void set_lock_used (bool used) {
                lock_used = used;
        }
@@ -112,17 +112,6 @@ public class Vala.Constant : Symbol, Lockable {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               if (!(parent_symbol is Block)) {
-                       // non-local constant
-                       context.analyzer.current_symbol = this;
-               }
-
                type_reference.check (context);
 
                if (!check_const_type (type_reference, context)) {
@@ -181,9 +170,6 @@ public class Vala.Constant : Symbol, Lockable {
                        Report.warning (source_reference, "%s hides inherited constant `%s'. Use the `new' 
keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                active = true;
 
                return !error;
diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala
index d16fc13..3d19596 100644
--- a/vala/valaconstructor.vala
+++ b/vala/valaconstructor.vala
@@ -67,12 +67,9 @@ public class Vala.Constructor : Subroutine {
 
                checked = true;
 
-               this_parameter = new Parameter ("this", new ObjectType (context.analyzer.current_class));
+               this_parameter = new Parameter ("this", new ObjectType (context.analyzer.get_current_class 
(this)));
                scope.add (this_parameter.name, this_parameter);
 
-               owner = context.analyzer.current_symbol.scope;
-               context.analyzer.current_symbol = this;
-
                if (body != null) {
                        body.check (context);
                }
@@ -83,8 +80,6 @@ public class Vala.Constructor : Subroutine {
                        }
                }
 
-               context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala
index 4d90534..7389b52 100644
--- a/vala/valacreationmethod.vala
+++ b/vala/valacreationmethod.vala
@@ -86,19 +86,11 @@ public class Vala.CreationMethod : Method {
 
                if (class_name != null && class_name != parent_symbol.name) {
                        // class_name is null for constructors generated by GIdlParser
-                       Report.error (source_reference, "missing return type in method `%s.%s´".printf 
(context.analyzer.current_symbol.get_full_name (), class_name));
+                       Report.error (source_reference, "missing return type in method `%s.%s´".printf 
(context.analyzer.get_current_symbol (this).get_full_name (), class_name));
                        error = true;
                        return false;
                }
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                int i = 0;
                foreach (Parameter param in get_parameters()) {
                        param.check (context);
@@ -130,40 +122,23 @@ public class Vala.CreationMethod : Method {
                        if (!chain_up && cl != null && cl.base_class != null) {
                                if (cl.base_class.default_construction_method != null
                                    && !cl.base_class.default_construction_method.has_construct_function) {
-                                       // directly chain up to Object
-                                       var old_insert_block = context.analyzer.insert_block;
-                                       context.analyzer.current_symbol = body;
-                                       context.analyzer.insert_block = body;
 
                                        var stmt = new ExpressionStatement (new MethodCall (new MemberAccess 
(new MemberAccess.simple ("GLib", source_reference), "Object", source_reference), source_reference), 
source_reference);
                                        body.insert_statement (0, stmt);
                                        stmt.check (context);
-
-                                       context.analyzer.current_symbol = this;
-                                       context.analyzer.insert_block = old_insert_block;
                                } else if (cl.base_class.default_construction_method == null
                                    || cl.base_class.default_construction_method.access == 
SymbolAccessibility.PRIVATE) {
                                        Report.error (source_reference, "unable to chain up to private base 
constructor");
                                } else if (cl.base_class.default_construction_method.get_required_arguments 
() > 0) {
                                        Report.error (source_reference, "unable to chain up to base 
constructor requiring arguments");
                                } else {
-                                       var old_insert_block = context.analyzer.insert_block;
-                                       context.analyzer.current_symbol = body;
-                                       context.analyzer.insert_block = body;
-
                                        var stmt = new ExpressionStatement (new MethodCall (new BaseAccess 
(source_reference), source_reference), source_reference);
                                        body.insert_statement (0, stmt);
                                        stmt.check (context);
-
-                                       context.analyzer.current_symbol = this;
-                                       context.analyzer.insert_block = old_insert_block;
                                }
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                if (is_abstract || is_virtual || overrides) {
                        Report.error (source_reference, "The creation method `%s' cannot be marked as 
override, virtual, or abstract".printf (get_full_name ()));
                        return false;
diff --git a/vala/valadelegate.vala b/vala/valadelegate.vala
index 258fe4d..b880634 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -124,7 +124,7 @@ public class Vala.Delegate : TypeSymbol, Callable {
        public List<Parameter> get_parameters () {
                return parameters;
        }
-
+       
        /**
         * Checks whether the arguments and return type of the specified method
         * matches this callback.
@@ -142,7 +142,7 @@ public class Vala.Delegate : TypeSymbol, Callable {
                if (!m.return_type.stricter (return_type.get_actual_type (dt, null, this))) {
                        return false;
                }
-
+               
                var method_params = m.get_parameters ();
                Iterator<Parameter> method_params_it = method_params.iterator ();
 
@@ -179,7 +179,7 @@ public class Vala.Delegate : TypeSymbol, Callable {
                                return false;
                        }
                }
-
+               
                /* method may not expect more arguments */
                if (method_params_it.next ()) {
                        return false;
@@ -219,9 +219,9 @@ public class Vala.Delegate : TypeSymbol, Callable {
                foreach (TypeParameter p in type_parameters) {
                        p.accept (visitor);
                }
-
+               
                return_type.accept (visitor);
-
+               
                foreach (Parameter param in parameters) {
                        param.accept (visitor);
                }
@@ -256,18 +256,12 @@ public class Vala.Delegate : TypeSymbol, Callable {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-
                foreach (TypeParameter p in type_parameters) {
                        p.check (context);
                }
-
+               
                return_type.check (context);
-
+               
                foreach (Parameter param in parameters) {
                        param.check (context);
                }
@@ -276,8 +270,6 @@ public class Vala.Delegate : TypeSymbol, Callable {
                        error_type.check (context);
                }
 
-               context.analyzer.current_source_file = old_source_file;
-
                return !error;
        }
 }
diff --git a/vala/valadestructor.vala b/vala/valadestructor.vala
index 7ee3843..ddfb0f9 100644
--- a/vala/valadestructor.vala
+++ b/vala/valadestructor.vala
@@ -67,15 +67,10 @@ public class Vala.Destructor : Subroutine {
 
                checked = true;
 
-               owner = context.analyzer.current_symbol.scope;
-               context.analyzer.current_symbol = this;
-
                if (body != null) {
                        body.check (context);
                }
 
-               context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valaenum.vala b/vala/valaenum.vala
index ad0a6b6..d2206d7 100644
--- a/vala/valaenum.vala
+++ b/vala/valaenum.vala
@@ -54,7 +54,7 @@ public class Vala.Enum : TypeSymbol {
        public Enum (string name, SourceReference? source_reference = null, Comment? comment = null) {
                base (name, source_reference, comment);
        }
-
+       
        /**
         * Appends the specified enum value to the list of values.
         *
@@ -75,7 +75,7 @@ public class Vala.Enum : TypeSymbol {
        public override void add_method (Method m) {
                if (m is CreationMethod) {
                        Report.error (m.source_reference, "construction methods may only be declared within 
classes and structs");
-
+               
                        m.error = true;
                        return;
                }
@@ -163,14 +163,6 @@ public class Vala.Enum : TypeSymbol {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                if (values.size <= 0) {
                        Report.error (source_reference, "Enum `%s' requires at least one value".printf 
(get_full_name ()));
                        error = true;
@@ -189,9 +181,6 @@ public class Vala.Enum : TypeSymbol {
                        c.check (context);
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valaerrorcode.vala b/vala/valaerrorcode.vala
index 93308ae..62ff540 100644
--- a/vala/valaerrorcode.vala
+++ b/vala/valaerrorcode.vala
@@ -29,7 +29,17 @@ public class Vala.ErrorCode : TypeSymbol {
        /**
         * Specifies the numerical representation of this enum value.
         */
-       public Expression value { get; set; }
+       public Expression? value {
+               get { return _value; }
+               set {
+                       _value = value;
+                       if (_value != null) {
+                               _value.parent_node = this;
+                       }
+               }
+       }
+
+       private Expression _value;
 
        /**
         * Creates a new enum value.
@@ -52,7 +62,7 @@ public class Vala.ErrorCode : TypeSymbol {
                this (name, source_reference);
                this.value = value;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_error_code (this);
        }
diff --git a/vala/valafield.vala b/vala/valafield.vala
index f060554..7ef631e 100644
--- a/vala/valafield.vala
+++ b/vala/valafield.vala
@@ -59,7 +59,7 @@ public class Vala.Field : Variable, Lockable {
 
        public override void accept_children (CodeVisitor visitor) {
                variable_type.accept (visitor);
-
+               
                if (initializer != null) {
                        initializer.accept (visitor);
                }
@@ -68,7 +68,7 @@ public class Vala.Field : Variable, Lockable {
        public bool get_lock_used () {
                return lock_used;
        }
-
+       
        public void set_lock_used (bool used) {
                lock_used = used;
        }
@@ -92,14 +92,6 @@ public class Vala.Field : Variable, Lockable {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                if (variable_type is VoidType) {
                        error = true;
                        Report.error (source_reference, "'void' not supported as field type");
@@ -190,9 +182,6 @@ public class Vala.Field : Variable, Lockable {
                        Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' 
keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 4d92842..2241066 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -38,12 +38,12 @@ public class Vala.ForeachStatement : Block {
                        }
                }
        }
-
+       
        /**
         * Specifies the element variable name.
         */
        public string variable_name { get; set; }
-
+       
        /**
         * Specifies the container.
         */
@@ -56,7 +56,7 @@ public class Vala.ForeachStatement : Block {
                        _collection.parent_node = this;
                }
        }
-
+       
        /**
         * Specifies the loop body.
         */
@@ -109,7 +109,7 @@ public class Vala.ForeachStatement : Block {
                this.body = body;
                this.type_reference = type_reference;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                if (use_iterator) {
                        base.accept (visitor);
@@ -154,6 +154,8 @@ public class Vala.ForeachStatement : Block {
 
                checked = true;
 
+               owner = context.analyzer.get_current_symbol (parent_node).scope;
+
                // analyze collection expression first, used for type inference
                if (!collection.check (context)) {
                        // ignore inner error
@@ -167,7 +169,7 @@ public class Vala.ForeachStatement : Block {
 
                var collection_type = collection.value_type.copy ();
                collection.target_type = collection_type.copy ();
-
+               
                if (collection_type.is_array ()) {
                        var array_type = (ArrayType) collection_type;
 
@@ -353,16 +355,10 @@ public class Vala.ForeachStatement : Block {
 
                element_variable = new LocalVariable (type_reference, variable_name, null, source_reference);
 
-               body.scope.add (variable_name, element_variable);
-
                body.add_local_variable (element_variable);
                element_variable.active = true;
                element_variable.checked = true;
 
-               // analyze body
-               owner = context.analyzer.current_symbol.scope;
-               context.analyzer.current_symbol = this;
-
                // call add_local_variable to check for shadowed variable
                add_local_variable (element_variable);
                remove_local_variable (element_variable);
@@ -373,8 +369,6 @@ public class Vala.ForeachStatement : Block {
                        local.active = false;
                }
 
-               context.analyzer.current_symbol = context.analyzer.current_symbol.parent_symbol;
-
                collection_variable = new LocalVariable (collection_type.copy (), "%s_collection".printf 
(variable_name));
 
                add_local_variable (collection_variable);
diff --git a/vala/valainterface.vala b/vala/valainterface.vala
index adb41ae..90e8eec 100644
--- a/vala/valainterface.vala
+++ b/vala/valainterface.vala
@@ -70,7 +70,7 @@ public class Vala.Interface : ObjectTypeSymbol {
        public List<DataType> get_prerequisites () {
                return prerequisites;
        }
-
+       
        /**
         * Adds the specified method as a member to this interface.
         *
@@ -79,7 +79,7 @@ public class Vala.Interface : ObjectTypeSymbol {
        public override void add_method (Method m) {
                if (m is CreationMethod) {
                        Report.error (m.source_reference, "construction methods may only be declared within 
classes and structs");
-
+               
                        m.error = true;
                        return;
                }
@@ -113,7 +113,7 @@ public class Vala.Interface : ObjectTypeSymbol {
                prop.this_parameter = new Parameter ("this", new ObjectType (this));
                prop.scope.add (prop.this_parameter.name, prop.this_parameter);
        }
-
+       
        public virtual List<Symbol> get_virtuals () {
                return virtuals;
        }
@@ -139,7 +139,7 @@ public class Vala.Interface : ObjectTypeSymbol {
                foreach (Method m in get_methods ()) {
                        m.accept (visitor);
                }
-
+               
                foreach (Field f in get_fields ()) {
                        f.accept (visitor);
                }
@@ -151,15 +151,15 @@ public class Vala.Interface : ObjectTypeSymbol {
                foreach (Property prop in get_properties ()) {
                        prop.accept (visitor);
                }
-
+               
                foreach (Signal sig in get_signals ()) {
                        sig.accept (visitor);
                }
-
+               
                foreach (Class cl in get_classes ()) {
                        cl.accept (visitor);
                }
-
+               
                foreach (Struct st in get_structs ()) {
                        st.accept (visitor);
                }
@@ -172,7 +172,7 @@ public class Vala.Interface : ObjectTypeSymbol {
        public override bool is_reference_type () {
                return true;
        }
-
+       
        public override bool is_subtype_of (TypeSymbol t) {
                if (this == t) {
                        return true;
@@ -183,10 +183,10 @@ public class Vala.Interface : ObjectTypeSymbol {
                                return true;
                        }
                }
-
+               
                return false;
        }
-
+       
        public override void replace_type (DataType old_type, DataType new_type) {
                for (int i = 0; i < prerequisites.size; i++) {
                        if (prerequisites[i] == old_type) {
@@ -204,14 +204,6 @@ public class Vala.Interface : ObjectTypeSymbol {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                foreach (DataType prerequisite_reference in get_prerequisites ()) {
                        // check whether prerequisite is at least as accessible as the interface
                        if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) {
@@ -374,9 +366,6 @@ public class Vala.Interface : ObjectTypeSymbol {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 3223e74..bd722fc 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -34,13 +34,13 @@ public class Vala.LambdaExpression : Expression {
         * expression_body or statement_body may be set.
         */
        public Expression expression_body { get; set; }
-
+       
        /**
         * The statement body of this lambda expression. Only one of
         * expression_body or statement_body may be set.
         */
        public Block statement_body { get; set; }
-
+       
        /**
         * The generated method.
         */
@@ -59,7 +59,7 @@ public class Vala.LambdaExpression : Expression {
                this.source_reference = source_reference;
                this.expression_body = expression_body;
        }
-
+       
        /**
         * Creates a new lambda expression with statement body.
         *
@@ -71,7 +71,7 @@ public class Vala.LambdaExpression : Expression {
                this.statement_body = statement_body;
                this.source_reference = source_reference;
        }
-
+       
        /**
         * Appends implicitly typed parameter.
         *
@@ -80,7 +80,7 @@ public class Vala.LambdaExpression : Expression {
        public void add_parameter (Parameter param) {
                parameters.add (param);
        }
-
+       
        /**
         * Returns copy of parameter list.
         *
@@ -89,7 +89,7 @@ public class Vala.LambdaExpression : Expression {
        public List<Parameter> get_parameters () {
                return parameters;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_lambda_expression (this);
 
@@ -137,10 +137,10 @@ public class Vala.LambdaExpression : Expression {
                method.used = true;
                method.version.check (source_reference);
 
-               if (!cb.has_target || !context.analyzer.is_in_instance_method ()) {
+               if (!cb.has_target || !context.analyzer.is_in_instance_method (this)) {
                        method.binding = MemberBinding.STATIC;
                } else {
-                       var sym = context.analyzer.current_symbol;
+                       var sym = context.analyzer.get_current_symbol (this);
                        while (method.this_parameter == null) {
                                if (sym is Property) {
                                        var prop = (Property) sym;
@@ -159,7 +159,7 @@ public class Vala.LambdaExpression : Expression {
                                sym = sym.parent_symbol;
                        }
                }
-               method.owner = context.analyzer.current_symbol.scope;
+               method.owner = context.analyzer.get_current_symbol (this).scope;
 
                var lambda_params = get_parameters ();
                Iterator<Parameter> lambda_param_it = lambda_params.iterator ();
@@ -218,7 +218,7 @@ public class Vala.LambdaExpression : Expression {
                method.body.owner = method.scope;
 
                // support use of generics in closures
-               var m = context.analyzer.find_parent_method (context.analyzer.current_symbol);
+               var m = context.analyzer.get_current_method (this);
                if (m != null) {
                        foreach (var type_param in m.get_type_parameters ()) {
                                method.add_type_parameter (new TypeParameter (type_param.name, 
type_param.source_reference));
diff --git a/vala/valalocalvariable.vala b/vala/valalocalvariable.vala
index 22d7c69..61013a9 100644
--- a/vala/valalocalvariable.vala
+++ b/vala/valalocalvariable.vala
@@ -43,7 +43,7 @@ public class Vala.LocalVariable : Variable {
        public LocalVariable (DataType? variable_type, string name, Expression? initializer = null, 
SourceReference? source_reference = null) {
                base (variable_type, name, initializer, source_reference);
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_local_variable (this);
        }
@@ -51,10 +51,10 @@ public class Vala.LocalVariable : Variable {
        public override void accept_children (CodeVisitor visitor) {
                if (initializer != null) {
                        initializer.accept (visitor);
-
+               
                        visitor.visit_end_full_expression (initializer);
                }
-
+               
                if (variable_type != null) {
                        variable_type.accept (visitor);
                }
@@ -189,11 +189,9 @@ public class Vala.LocalVariable : Variable {
                        }
                }
 
-               context.analyzer.current_symbol.scope.add (name, this);
-
                // current_symbol is a Method if this is the `result'
                // variable used for postconditions
-               var block = context.analyzer.current_symbol as Block;
+               var block = context.analyzer.get_current_block (this);
                if (block != null) {
                        block.add_local_variable (this);
                }
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
index ad15d06..b94e88c 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -36,19 +36,36 @@ public class Vala.LockStatement : CodeNode, Statement {
        /**
         * Expression representing the resource to be locked.
         */
-       public Expression resource { get; set; }
-
+       public Expression resource {
+               get { return _resource; }
+               set {
+                       _resource = value;
+                       _resource.parent_node = this;
+               }
+       }
+       
        /**
         * The statement during its execution the resource is locked.
         */
-       public Block? body { get; set; }
+       public Block? body {
+               get { return _body; }
+               set {
+                       _body = value;
+                       if (_body != null) {
+                               _body.parent_node = this;
+                       }
+               }
+       }
+
+       private Expression _resource;
+       private Block _body;
 
        public LockStatement (Expression resource, Block? body, SourceReference? source_reference = null) {
                this.body = body;
                this.source_reference = source_reference;
                this.resource = resource;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                resource.accept (visitor);
                if (body != null) {
@@ -91,7 +108,7 @@ public class Vala.LockStatement : CodeNode, Statement {
                }
 
                /* parent symbol must be the current class */
-               if (resource.symbol_reference.parent_symbol != context.analyzer.current_class) {
+               if (resource.symbol_reference.parent_symbol != context.analyzer.get_current_class (this)) {
                        error = true;
                        resource.error = true;
                        Report.error (resource.source_reference, "Only members of the current class are 
lockable");
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index a5e056f..a8296d3 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -40,7 +40,7 @@ public class Vala.MemberAccess : Expression {
                        }
                }
        }
-
+       
        /**
         * The name of the member.
         */
@@ -69,7 +69,7 @@ public class Vala.MemberAccess : Expression {
 
        private Expression? _inner;
        private List<DataType> type_argument_list = new ArrayList<DataType> ();
-
+       
        /**
         * Creates a new member access expression.
         *
@@ -105,7 +105,7 @@ public class Vala.MemberAccess : Expression {
                type_argument_list.add (arg);
                arg.parent_node = this;
        }
-
+       
        /**
         * Returns a copy of the list of generic type arguments.
         *
@@ -125,7 +125,7 @@ public class Vala.MemberAccess : Expression {
                if (inner != null) {
                        inner.accept (visitor);
                }
-
+               
                foreach (DataType type_arg in type_argument_list) {
                        type_arg.accept (visitor);
                }
@@ -203,7 +203,7 @@ public class Vala.MemberAccess : Expression {
                if (inner != null) {
                        inner.check (context);
                }
-
+               
                foreach (DataType type_arg in type_argument_list) {
                        type_arg.check (context);
                }
@@ -220,20 +220,20 @@ public class Vala.MemberAccess : Expression {
                        symbol_reference = base_symbol.scope.lookup (member_name);
                } else if (inner == null) {
                        if (member_name == "this") {
-                               if (!context.analyzer.is_in_instance_method ()) {
+                               if (!context.analyzer.is_in_instance_method (this)) {
                                        error = true;
                                        Report.error (source_reference, "This access invalid outside of 
instance methods");
                                        return false;
                                }
                        }
 
-                       base_symbol = context.analyzer.current_symbol;
+                       base_symbol = context.analyzer.get_current_symbol (this);
 
                        // track whether method has been found to make sure that access
                        // to instance member is denied from within static lambda expressions
                        bool method_found = false;
 
-                       var sym = context.analyzer.current_symbol;
+                       var sym = base_symbol;
                        while (sym != null && symbol_reference == null) {
                                if (!method_found) {
                                        if (sym is CreationMethod) {
@@ -487,13 +487,15 @@ public class Vala.MemberAccess : Expression {
                        return false;
                }
 
+               var current_method_or_property_accessor = 
context.analyzer.get_current_method_or_property_accessor (this);
+
                if (member is LocalVariable) {
                        var local = (LocalVariable) member;
                        var block = local.parent_symbol as Block;
-                       if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) 
!= context.analyzer.current_method_or_property_accessor) {
+                       if (block != null && context.analyzer.get_current_method_or_property_accessor (block) 
!= current_method_or_property_accessor) {
                                // mark all methods between current method and the captured
                                // block as closures (to support nested closures)
-                               Symbol sym = context.analyzer.current_method_or_property_accessor;
+                               Symbol sym = current_method_or_property_accessor;
                                while (sym != block) {
                                        var method = sym as Method;
                                        if (method != null) {
@@ -511,10 +513,10 @@ public class Vala.MemberAccess : Expression {
                } else if (member is Parameter) {
                        var param = (Parameter) member;
                        var m = param.parent_symbol as Method;
-                       if (m != null && m != context.analyzer.current_method_or_property_accessor && param 
!= m.this_parameter) {
+                       if (m != null && m != current_method_or_property_accessor && param != 
m.this_parameter) {
                                // mark all methods between current method and the captured
                                // parameter as closures (to support nested closures)
-                               Symbol sym = context.analyzer.current_method_or_property_accessor;
+                               Symbol sym = current_method_or_property_accessor;
                                while (sym != m) {
                                        var method = sym as Method;
                                        if (method != null) {
@@ -532,10 +534,10 @@ public class Vala.MemberAccess : Expression {
                                }
                        } else {
                                var acc = param.parent_symbol.parent_symbol as PropertyAccessor;
-                               if (acc != null && acc != 
context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
+                               if (acc != null && acc != current_method_or_property_accessor && param != 
acc.prop.this_parameter) {
                                        // mark all methods between current method and the captured
                                        // parameter as closures (to support nested closures)
-                                       Symbol sym = context.analyzer.current_method_or_property_accessor;
+                                       Symbol sym = current_method_or_property_accessor;
                                        while (sym != m) {
                                                var method = sym as Method;
                                                if (method != null) {
@@ -564,7 +566,7 @@ public class Vala.MemberAccess : Expression {
                        access = c.access;
 
                        var block = c.parent_symbol as Block;
-                       if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) 
!= context.analyzer.current_method_or_property_accessor) {
+                       if (block != null && context.analyzer.get_current_method_or_property_accessor (block) 
!= current_method_or_property_accessor) {
                                error = true;
                                Report.error (source_reference, "internal error: accessing local constants of 
outer methods is not supported yet");
                                return false;
@@ -574,7 +576,7 @@ public class Vala.MemberAccess : Expression {
                        if (m.is_async_callback) {
                                // ensure to use right callback method for virtual/abstract async methods
                                // and also for lambda expressions within async methods
-                               var async_method = context.analyzer.current_async_method;
+                               var async_method = context.analyzer.get_current_async_method (this);
 
                                bool is_valid_access = false;
                                if (async_method != null) {
@@ -592,14 +594,11 @@ public class Vala.MemberAccess : Expression {
                                        return false;
                                }
 
-                               if (async_method != context.analyzer.current_method) {
-                                       Symbol sym = context.analyzer.current_method;
-                                       while (sym != async_method) {
-                                               var method = sym as Method;
-                                               if (method != null) {
-                                                       method.closure = true;
-                                               }
-                                               sym = sym.parent_symbol;
+                               var current_method = context.analyzer.get_current_method (this);
+                               if (async_method != current_method) {
+                                       while (current_method != async_method) {
+                                               current_method.closure = true;
+                                               current_method = context.analyzer.get_current_method 
(current_method.parent_symbol);
                                        }
                                        async_method.body.captured = true;
                                }
@@ -715,7 +714,7 @@ public class Vala.MemberAccess : Expression {
                        var target_type = (TypeSymbol) member.parent_symbol;
 
                        bool in_subtype = false;
-                       for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; 
this_symbol = this_symbol.parent_symbol) {
+                       for (Symbol this_symbol = context.analyzer.get_current_symbol (this); this_symbol != 
null; this_symbol = this_symbol.parent_symbol) {
                                if (this_symbol == target_type) {
                                        // required for interfaces with non-abstract methods
                                        // accessing protected interface members
@@ -739,7 +738,7 @@ public class Vala.MemberAccess : Expression {
                        var target_type = member.parent_symbol;
 
                        bool in_target_type = false;
-                       for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; 
this_symbol = this_symbol.parent_symbol) {
+                       for (Symbol this_symbol = context.analyzer.get_current_symbol (this); this_symbol != 
null; this_symbol = this_symbol.parent_symbol) {
                                if (target_type == this_symbol) {
                                        in_target_type = true;
                                        break;
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 1adfeab..638fe3c 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -696,14 +696,6 @@ public class Vala.Method : Subroutine, Callable {
                        return false;
                }
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                return_type.check (context);
 
                var init_attr = get_attribute ("ModuleInit");
@@ -770,7 +762,7 @@ public class Vala.Method : Subroutine, Callable {
                        body.check (context);
                }
 
-               if (context.analyzer.current_struct != null) {
+               if (context.analyzer.get_current_struct (this) != null) {
                        if (is_abstract || is_virtual || overrides) {
                                error = true;
                                Report.error (source_reference, "A struct member `%s' cannot be marked as 
override, virtual, or abstract".printf (get_full_name ()));
@@ -798,9 +790,6 @@ public class Vala.Method : Subroutine, Callable {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                if (!external_package && !overrides && !hides && get_hidden_member () != null) {
                        Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' 
keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
                }
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index 62d51dd..1ff013b 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -233,7 +233,7 @@ public class Vala.MethodCall : Expression {
                CreationMethod base_cm = null;
 
                if (is_chainup) {
-                       var cm = context.analyzer.find_current_method () as CreationMethod;
+                       var cm = context.analyzer.get_current_method (this) as CreationMethod;
                        if (cm == null) {
                                error = true;
                                Report.error (source_reference, "invocation not supported in this context");
@@ -480,7 +480,8 @@ public class Vala.MethodCall : Expression {
                                        error = true;
                                        Report.error (source_reference, "yield expression requires async 
method");
                                }
-                               if (context.analyzer.current_method == null || 
!context.analyzer.current_method.coroutine) {
+                               var current_method = context.analyzer.get_current_method (this);
+                               if (current_method == null || !current_method.coroutine) {
                                        error = true;
                                        Report.error (source_reference, "yield expression not available 
outside async method");
                                }
@@ -627,7 +628,7 @@ public class Vala.MethodCall : Expression {
                if (may_throw) {
                        if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
                                // simple statements, no side effects after method call
-                       } else if (!(context.analyzer.current_symbol is Block)) {
+                       } else if (!(context.analyzer.get_current_symbol (this) is Block)) {
                                // can't handle errors in field initializers
                                Report.error (source_reference, "Field initializers must not throw errors");
                        } else {
@@ -637,7 +638,7 @@ public class Vala.MethodCall : Expression {
                                var local = new LocalVariable (value_type.copy (), get_temp_name (), null, 
source_reference);
                                var decl = new DeclarationStatement (local, source_reference);
 
-                               insert_statement (context.analyzer.insert_block, decl);
+                               insert_statement (context.analyzer.get_insert_block (this), decl);
 
                                var temp_access = SemanticAnalyzer.create_temp_access (local, target_type);
 
@@ -648,9 +649,9 @@ public class Vala.MethodCall : Expression {
                                // move temp variable to insert block to ensure the
                                // variable is in the same block as the declaration
                                // otherwise there will be scoping issues in the generated code
-                               var block = (Block) context.analyzer.current_symbol;
+                               var block = context.analyzer.get_current_block (this);
                                block.remove_local_variable (local);
-                               context.analyzer.insert_block.add_local_variable (local);
+                               context.analyzer.get_insert_block (this).add_local_variable (local);
 
                                old_parent_node.replace_expression (this, temp_access);
                                temp_access.check (context);
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index d3b01c2..e9038bf 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -41,7 +41,13 @@ public class Vala.ObjectCreationExpression : Expression {
         * The construction method to use or the data type to be created
         * with the default construction method.
         */
-       public MemberAccess member_name { get; set; }
+       public MemberAccess member_name {
+               get { return _member_name; }
+               set {
+                       _member_name = value;
+                       _member_name.parent_node = this;
+               }
+       }
 
        public bool is_yield_expression { get; set; }
 
@@ -52,6 +58,7 @@ public class Vala.ObjectCreationExpression : Expression {
        private List<MemberInitializer> object_initializer = new ArrayList<MemberInitializer> ();
 
        private DataType _data_type;
+       private MemberAccess _member_name;
 
        /**
         * Creates a new object creation expression.
@@ -286,7 +293,7 @@ public class Vala.ObjectCreationExpression : Expression {
                        if (symbol_reference != null
                            && (symbol_reference.access == SymbolAccessibility.PRIVATE || 
symbol_reference.access == SymbolAccessibility.PROTECTED)) {
                                bool in_target_type = false;
-                               for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != 
null; this_symbol = this_symbol.parent_symbol) {
+                               for (Symbol this_symbol = context.analyzer.get_current_symbol (this); 
this_symbol != null; this_symbol = this_symbol.parent_symbol) {
                                        if (this_symbol == cl) {
                                                in_target_type = true;
                                                break;
@@ -354,7 +361,8 @@ public class Vala.ObjectCreationExpression : Expression {
                                        error = true;
                                        Report.error (source_reference, "yield expression requires async 
method");
                                }
-                               if (context.analyzer.current_method == null || 
!context.analyzer.current_method.coroutine) {
+                               var current_method = context.analyzer.get_current_method (this);
+                               if (current_method == null || !current_method.coroutine) {
                                        error = true;
                                        Report.error (source_reference, "yield expression not available 
outside async method");
                                }
@@ -487,7 +495,7 @@ public class Vala.ObjectCreationExpression : Expression {
                if (may_throw) {
                        if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
                                // simple statements, no side effects after method call
-                       } else if (!(context.analyzer.current_symbol is Block)) {
+                       } else if (!(context.analyzer.get_current_symbol (this) is Block)) {
                                // can't handle errors in field initializers
                                Report.error (source_reference, "Field initializers must not throw errors");
                        } else {
@@ -497,7 +505,7 @@ public class Vala.ObjectCreationExpression : Expression {
                                var local = new LocalVariable (value_type.copy (), get_temp_name (), null, 
source_reference);
                                var decl = new DeclarationStatement (local, source_reference);
 
-                               insert_statement (context.analyzer.insert_block, decl);
+                               insert_statement (context.analyzer.get_insert_block (this), decl);
 
                                var temp_access = SemanticAnalyzer.create_temp_access (local, target_type);
                                // don't set initializer earlier as this changes parent_node and 
parent_statement
@@ -507,9 +515,9 @@ public class Vala.ObjectCreationExpression : Expression {
                                // move temp variable to insert block to ensure the
                                // variable is in the same block as the declaration
                                // otherwise there will be scoping issues in the generated code
-                               var block = (Block) context.analyzer.current_symbol;
+                               var block = context.analyzer.get_current_block (this);
                                block.remove_local_variable (local);
-                               context.analyzer.insert_block.add_local_variable (local);
+                               context.analyzer.get_insert_block (this).add_local_variable (local);
 
                                old_parent_node.replace_expression (this, temp_access);
                                temp_access.check (context);
diff --git a/vala/valaparameter.vala b/vala/valaparameter.vala
index bfc340b..c878287 100644
--- a/vala/valaparameter.vala
+++ b/vala/valaparameter.vala
@@ -35,13 +35,13 @@ public class Vala.Parameter : Variable {
         * parameters.
         */
        public bool ellipsis { get; set; }
-
+       
        /**
         * Specifies whether the methods accepts an indefinite number of
         * parameters.
         */
        public bool params_array { get; set; }
-
+       
        public bool captured { get; set; }
 
        public bool format_arg {
@@ -68,7 +68,7 @@ public class Vala.Parameter : Variable {
 
                access = SymbolAccessibility.PUBLIC;
        }
-
+       
        /**
         * Creates a new ellipsis parameter representing an indefinite number of
         * parameters.
@@ -87,7 +87,7 @@ public class Vala.Parameter : Variable {
        public override void accept_children (CodeVisitor visitor) {
                if (!ellipsis) {
                        variable_type.accept (visitor);
-
+                       
                        if (initializer != null) {
                                initializer.accept (visitor);
                        }
@@ -132,14 +132,6 @@ public class Vala.Parameter : Variable {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = parent_symbol;
-
                if (variable_type != null) {
                        if (variable_type is VoidType) {
                                error = true;
@@ -151,7 +143,7 @@ public class Vala.Parameter : Variable {
 
                if (!ellipsis) {
                        variable_type.check (context);
-
+                       
                        if (params_array && !(variable_type is ArrayType)) {
                                error = true;
                                Report.error (source_reference, "parameter array expected");
@@ -204,9 +196,6 @@ public class Vala.Parameter : Variable {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valaproperty.vala b/vala/valaproperty.vala
index 2a83295..649994f 100644
--- a/vala/valaproperty.vala
+++ b/vala/valaproperty.vala
@@ -39,7 +39,7 @@ public class Vala.Property : Symbol, Lockable {
                        }
                }
        }
-
+       
        /**
         * The get accessor of this property if available.
         */
@@ -52,7 +52,7 @@ public class Vala.Property : Symbol, Lockable {
                        }
                }
        }
-
+       
        /**
         * The set/construct accessor of this property if available.
         */
@@ -65,7 +65,7 @@ public class Vala.Property : Symbol, Lockable {
                        }
                }
        }
-
+       
        /**
         * Represents the generated `this` parameter in this property.
         */
@@ -76,20 +76,20 @@ public class Vala.Property : Symbol, Lockable {
         * disabled.
         */
        public bool interface_only { get; set; }
-
+       
        /**
         * Specifies whether this property is abstract. Abstract properties have
         * no accessor bodies, may only be specified within abstract classes and
         * interfaces, and must be overriden by derived non-abstract classes.
         */
        public bool is_abstract { get; set; }
-
+       
        /**
         * Specifies whether this property is virtual. Virtual properties may be
         * overridden by derived classes.
         */
        public bool is_virtual { get; set; }
-
+       
        /**
         * Specifies whether this property overrides a virtual or abstract
         * property of a base type.
@@ -160,7 +160,7 @@ public class Vala.Property : Symbol, Lockable {
                        return _base_property;
                }
        }
-
+       
        /**
         * Specifies the abstract interface property this property implements.
         */
@@ -222,7 +222,7 @@ public class Vala.Property : Symbol, Lockable {
 
        public override void accept_children (CodeVisitor visitor) {
                property_type.accept (visitor);
-
+               
                if (get_accessor != null) {
                        get_accessor.accept (visitor);
                }
@@ -238,11 +238,11 @@ public class Vala.Property : Symbol, Lockable {
        public bool get_lock_used () {
                return lock_used;
        }
-
+       
        public void set_lock_used (bool used) {
                lock_used = used;
        }
-
+       
        /**
         * Checks whether the accessors of this property are compatible
         * with the specified base property.
@@ -424,14 +424,6 @@ public class Vala.Property : Symbol, Lockable {
                        }
                }
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                if (property_type is VoidType) {
                        error = true;
                        Report.error (source_reference, "'void' not supported as property type");
@@ -484,9 +476,6 @@ public class Vala.Property : Symbol, Lockable {
                        Report.error (initializer.source_reference, "Expected initializer of type `%s' but 
got `%s'".printf (property_type.to_string (), initializer.value_type.to_string ()));
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala
index 73d8c82..ccc1be5 100644
--- a/vala/valapropertyaccessor.vala
+++ b/vala/valapropertyaccessor.vala
@@ -50,12 +50,12 @@ public class Vala.PropertyAccessor : Subroutine {
         * Specifies whether this accessor may be used to get the property.
         */
        public bool readable { get; private set; }
-
+       
        /**
         * Specifies whether this accessor may be used to set the property.
         */
        public bool writable { get; private set; }
-
+       
        /**
         * Specifies whether this accessor may be used to construct the
         * property.
@@ -77,7 +77,7 @@ public class Vala.PropertyAccessor : Subroutine {
        public Parameter value_parameter { get; private set; }
 
        private DataType _value_type;
-
+       
        /**
         * Creates a new property accessor.
         *
@@ -150,10 +150,6 @@ public class Vala.PropertyAccessor : Subroutine {
                        return false;
                }
 
-               var old_symbol = context.analyzer.current_symbol;
-
-               context.analyzer.current_symbol = this;
-
                if (writable || construction) {
                        value_parameter = new Parameter ("value", value_type, source_reference);
                }
@@ -198,8 +194,6 @@ public class Vala.PropertyAccessor : Subroutine {
                        }
                }
 
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 
diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala
index 2cb1e6d..9cc8017 100644
--- a/vala/valareturnstatement.vala
+++ b/vala/valareturnstatement.vala
@@ -59,7 +59,7 @@ public class Vala.ReturnStatement : CodeNode, Statement {
        public override void accept_children (CodeVisitor visitor) {
                if (return_expression != null) {
                        return_expression.accept (visitor);
-
+               
                        visitor.visit_end_full_expression (return_expression);
                }
        }
@@ -77,8 +77,10 @@ public class Vala.ReturnStatement : CodeNode, Statement {
 
                checked = true;
 
+               var current_return_type = context.analyzer.get_current_return_type (this);
+
                if (return_expression != null) {
-                       return_expression.target_type = context.analyzer.current_return_type;
+                       return_expression.target_type = current_return_type;
                }
 
                if (return_expression != null && !return_expression.check (context)) {
@@ -87,21 +89,21 @@ public class Vala.ReturnStatement : CodeNode, Statement {
                        return false;
                }
 
-               if (context.analyzer.current_return_type == null) {
+               if (current_return_type == null) {
                        error = true;
                        Report.error (source_reference, "Return not allowed in this context");
                        return false;
                }
 
                if (return_expression == null) {
-                       if (!(context.analyzer.current_return_type is VoidType)) {
+                       if (!(current_return_type is VoidType)) {
                                error = true;
                                Report.error (source_reference, "Return without value in non-void function");
                        }
                        return !error;
                }
 
-               if (context.analyzer.current_return_type is VoidType) {
+               if (current_return_type is VoidType) {
                        Report.error (source_reference, "Return with value in void function");
                        return false;
                }
@@ -112,14 +114,14 @@ public class Vala.ReturnStatement : CodeNode, Statement {
                        return false;
                }
 
-               if (!return_expression.value_type.compatible (context.analyzer.current_return_type)) {
+               if (!return_expression.value_type.compatible (current_return_type)) {
                        error = true;
-                       Report.error (source_reference, "Return: Cannot convert from `%s' to `%s'".printf 
(return_expression.value_type.to_string (), context.analyzer.current_return_type.to_string ()));
+                       Report.error (source_reference, "Return: Cannot convert from `%s' to `%s'".printf 
(return_expression.value_type.to_string (), current_return_type.to_string ()));
                        return false;
                }
 
                if (return_expression.value_type.is_disposable () &&
-                   !context.analyzer.current_return_type.value_owned) {
+                   !current_return_type.value_owned) {
                        error = true;
                        Report.error (source_reference, "Return value transfers ownership but method return 
type hasn't been declared to transfer ownership");
                        return false;
@@ -127,15 +129,15 @@ public class Vala.ReturnStatement : CodeNode, Statement {
 
                var local = return_expression.symbol_reference as LocalVariable;
                if (local != null && local.variable_type.is_disposable () &&
-                   !context.analyzer.current_return_type.value_owned) {
+                   !current_return_type.value_owned) {
                        error = true;
                        Report.error (source_reference, "Local variable with strong reference used as return 
value and method return type has not been declared to transfer ownership");
                        return false;
                }
 
                if (return_expression is NullLiteral
-                   && !context.analyzer.current_return_type.nullable) {
-                       Report.warning (source_reference, "`null' incompatible with return type `%s`".printf 
(context.analyzer.current_return_type.to_string ()));
+                   && !current_return_type.nullable) {
+                       Report.warning (source_reference, "`null' incompatible with return type `%s`".printf 
(current_return_type.to_string ()));
                }
 
                add_error_types (return_expression.get_error_types ());
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 73b0b61..a641707 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -30,108 +30,6 @@ using GLib;
 public class Vala.SemanticAnalyzer : CodeVisitor {
        CodeContext context;
 
-       public Symbol current_symbol { get; set; }
-       public SourceFile current_source_file { get; set; }
-
-       public TypeSymbol? current_type_symbol {
-               get {
-                       var sym = current_symbol;
-                       while (sym != null) {
-                               if (sym is TypeSymbol) {
-                                       return (TypeSymbol) sym;
-                               }
-                               sym = sym.parent_symbol;
-                       }
-                       return null;
-               }
-       }
-
-       public Class? current_class {
-               get { return current_type_symbol as Class; }
-       }
-
-
-       public Struct? current_struct {
-               get { return current_type_symbol as Struct; }
-       }
-
-       public Method? current_method {
-               get {
-                       unowned Symbol sym = current_symbol;
-                       while (sym is Block) {
-                               sym = sym.parent_symbol;
-                       }
-                       return sym as Method;
-               }
-       }
-
-       public Method? current_async_method {
-               get {
-                       unowned Symbol sym = current_symbol;
-                       while (sym is Block || sym is Method) {
-                               var m = sym as Method;
-                               if (m != null && m.coroutine) {
-                                       break;
-                               }
-
-                               sym = sym.parent_symbol;
-                       }
-                       return sym as Method;
-               }
-       }
-
-       public PropertyAccessor? current_property_accessor {
-               get {
-                       unowned Symbol sym = current_symbol;
-                       while (sym is Block) {
-                               sym = sym.parent_symbol;
-                       }
-                       return sym as PropertyAccessor;
-               }
-       }
-
-       public Symbol? current_method_or_property_accessor {
-               get {
-                       unowned Symbol sym = current_symbol;
-                       while (sym is Block) {
-                               sym = sym.parent_symbol;
-                       }
-                       if (sym is Method) {
-                               return sym;
-                       } else if (sym is PropertyAccessor) {
-                               return sym;
-                       } else {
-                               return null;
-                       }
-               }
-       }
-
-       public DataType? current_return_type {
-               get {
-                       var m = current_method;
-                       if (m != null) {
-                               return m.return_type;
-                       }
-
-                       var acc = current_property_accessor;
-                       if (acc != null) {
-                               if (acc.readable) {
-                                       return acc.value_type;
-                               } else {
-                                       return void_type;
-                               }
-                       }
-
-                       if (is_in_constructor () || is_in_destructor ()) {
-                               return void_type;
-                       }
-
-                       return null;
-               }
-       }
-
-       public Block insert_block;
-
        public DataType void_type = new VoidType ();
        public DataType bool_type;
        public DataType string_type;
@@ -217,7 +115,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                gsource_type = (Class) glib_ns.scope.lookup ("Source");
 
-               current_symbol = root_symbol;
                context.root.check (context);
                context.accept (this);
 
@@ -225,11 +122,115 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        }
 
        public override void visit_source_file (SourceFile file) {
-               current_source_file = file;
-
                file.check (context);
        }
 
+       public unowned Symbol get_current_symbol (CodeNode node) {
+               while (!(node is Symbol) || is_local_symbol ((Symbol) node)) {
+                       node = node.parent_node;
+               }
+               return (Symbol) node;
+       }
+
+       public bool is_local_symbol (Symbol sym) {
+               if (sym is LocalVariable) {
+                       return true;
+               }
+               if (sym is Constant && sym.parent_symbol is Block) {
+                       return true;
+               }
+               return false;
+       }
+
+       public unowned TypeSymbol? get_current_type_symbol (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
+               while (sym != null && !(sym is TypeSymbol)) {
+                       sym = sym.parent_symbol;
+               }
+               return (TypeSymbol) sym;
+       }
+
+       public unowned Class? get_current_class (CodeNode node) {
+               return get_current_type_symbol (node) as Class;
+       }
+
+
+       public unowned Struct? get_current_struct (CodeNode node) {
+               return get_current_type_symbol (node) as Struct;
+       }
+
+       public unowned Method? get_current_method (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
+               while (sym is Block) {
+                       sym = sym.parent_symbol;
+               }
+               return sym as Method;
+       }
+
+       public unowned Method? get_current_async_method (CodeNode node) {
+               unowned Method m = get_current_method (node);
+               while (m != null && !m.coroutine) {
+                       m = get_current_method (m.parent_symbol);
+               }
+               return m;
+       }
+
+       public unowned PropertyAccessor? get_current_property_accessor (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
+               while (sym is Block) {
+                       sym = sym.parent_symbol;
+               }
+               return sym as PropertyAccessor;
+       }
+
+       public unowned Symbol? get_current_method_or_property_accessor (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
+               while (sym is Block) {
+                       sym = sym.parent_symbol;
+               }
+               if (sym is Method) {
+                       return sym;
+               } else if (sym is PropertyAccessor) {
+                       return sym;
+               } else {
+                       return null;
+               }
+       }
+
+       public unowned DataType? get_current_return_type (CodeNode node) {
+               unowned Method m = get_current_method (node);
+               if (m != null) {
+                       return m.return_type;
+               }
+
+               unowned PropertyAccessor acc = get_current_property_accessor (node);
+               if (acc != null) {
+                       if (acc.readable) {
+                               return acc.value_type;
+                       } else {
+                               return void_type;
+                       }
+               }
+
+               if (is_in_constructor (node) || is_in_destructor (node)) {
+                       return void_type;
+               }
+
+               return null;
+       }
+
+       public unowned Block? get_current_block (CodeNode node) {
+               return get_current_symbol (node) as Block;
+       }
+
+       public unowned Block? get_insert_block (CodeNode node) {
+               unowned Block? block = get_current_block (node);
+               if (block is ForeachStatement) {
+                       block = block.parent_symbol as Block;
+               }
+               return block;
+       }
+
        // check whether type is at least as accessible as the specified symbol
        public bool is_type_accessible (Symbol sym, DataType type) {
                return type.is_accessible (sym);
@@ -888,8 +889,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return actual_type;
        }
 
-       public bool is_in_instance_method () {
-               var sym = current_symbol;
+       public bool is_in_instance_method (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
                while (sym != null) {
                        if (sym is CreationMethod) {
                                return true;
@@ -1006,39 +1007,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                }
        }
 
-       public Method? find_current_method () {
-               var sym = current_symbol;
-               while (sym != null) {
-                       if (sym is Method) {
-                               return (Method) sym;
-                       }
-                       sym = sym.parent_symbol;
-               }
-               return null;
-       }
-
-       public Method? find_parent_method (Symbol sym) {
-               while (sym is Block) {
-                       sym = sym.parent_symbol;
-               }
-               return sym as Method;
-       }
-
-       public Symbol? find_parent_method_or_property_accessor (Symbol sym) {
-               while (sym is Block) {
-                       sym = sym.parent_symbol;
-               }
-               if (sym is Method) {
-                       return sym;
-               } else if (sym is PropertyAccessor) {
-                       return sym;
-               } else {
-                       return null;
-               }
-       }
-
-       public bool is_in_constructor () {
-               var sym = current_symbol;
+       public bool is_in_constructor (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
                while (sym != null) {
                        if (sym is Constructor) {
                                return true;
@@ -1048,8 +1018,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return false;
        }
 
-       public bool is_in_destructor () {
-               var sym = current_symbol;
+       public bool is_in_destructor (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
                while (sym != null) {
                        if (sym is Destructor) {
                                return true;
diff --git a/vala/valastruct.vala b/vala/valastruct.vala
index 972b4bd..feff638 100644
--- a/vala/valastruct.vala
+++ b/vala/valastruct.vala
@@ -144,7 +144,7 @@ public class Vala.Struct : TypeSymbol {
                type_parameters.add (p);
                scope.add (p.name, p);
        }
-
+       
        /**
         * Returns a copy of the type parameter list.
         *
@@ -163,7 +163,7 @@ public class Vala.Struct : TypeSymbol {
                constants.add (c);
                scope.add (c.name, c);
        }
-
+       
        /**
         * Adds the specified field as a member to this struct.
         *
@@ -175,7 +175,7 @@ public class Vala.Struct : TypeSymbol {
                fields.add (f);
                scope.add (f.name, f);
        }
-
+       
        /**
         * Returns a copy of the list of fields.
         *
@@ -201,7 +201,7 @@ public class Vala.Struct : TypeSymbol {
         */
        public override void add_method (Method m) {
                return_if_fail (m != null);
-
+               
                if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
                        m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol 
(this));
                        m.scope.add (m.this_parameter.name, m.this_parameter);
@@ -228,7 +228,7 @@ public class Vala.Struct : TypeSymbol {
                methods.add (m);
                scope.add (m.name, m);
        }
-
+       
        /**
         * Returns a copy of the list of methods.
         *
@@ -276,15 +276,15 @@ public class Vala.Struct : TypeSymbol {
                foreach (TypeParameter p in type_parameters) {
                        p.accept (visitor);
                }
-
+               
                foreach (Field f in fields) {
                        f.accept (visitor);
                }
-
+               
                foreach (Constant c in constants) {
                        c.accept (visitor);
                }
-
+               
                foreach (Method m in methods) {
                        m.accept (visitor);
                }
@@ -325,7 +325,7 @@ public class Vala.Struct : TypeSymbol {
                }
                return integer_type;
        }
-
+       
        /**
         * Returns whether this is a floating point type.
         *
@@ -388,14 +388,14 @@ public class Vala.Struct : TypeSymbol {
 
        public override int get_type_parameter_index (string name) {
                int i = 0;
-
+               
                foreach (TypeParameter p in type_parameters) {
                        if (p.name == name) {
                                return (i);
                        }
                        i++;
                }
-
+               
                return -1;
        }
 
@@ -481,14 +481,6 @@ public class Vala.Struct : TypeSymbol {
 
                checked = true;
 
-               var old_source_file = context.analyzer.current_source_file;
-               var old_symbol = context.analyzer.current_symbol;
-
-               if (source_reference != null) {
-                       context.analyzer.current_source_file = source_reference.file;
-               }
-               context.analyzer.current_symbol = this;
-
                if (base_type != null) {
                        base_type.check (context);
 
@@ -546,9 +538,6 @@ public class Vala.Struct : TypeSymbol {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-               context.analyzer.current_symbol = old_symbol;
-
                return !error;
        }
 }
diff --git a/vala/valasubroutine.vala b/vala/valasubroutine.vala
index e9c05ac..0ef8bf3 100644
--- a/vala/valasubroutine.vala
+++ b/vala/valasubroutine.vala
@@ -45,7 +45,6 @@ public abstract class Vala.Subroutine : Symbol {
                set {
                        _body = value;
                        if (_body != null) {
-                               _body.owner = scope;
                                _body.parent_node = this;
                        }
                }
diff --git a/vala/valaswitchlabel.vala b/vala/valaswitchlabel.vala
index 70eb7e3..4996bdd 100644
--- a/vala/valaswitchlabel.vala
+++ b/vala/valaswitchlabel.vala
@@ -29,9 +29,19 @@ public class Vala.SwitchLabel : CodeNode {
        /**
         * Specifies the label expression.
         */
-       public Expression expression { get; set; }
+       public Expression expression {
+               get { return _expression; }
+               set {
+                       _expression = value;
+                       _expression.parent_node = this;
+               }
+       }
+
+       public weak SwitchSection section {
+               get { return (SwitchSection) parent_node; }
+       }
 
-       public weak SwitchSection section { get; set; }
+       private Expression _expression;
 
        /**
         * Creates a new switch case label.
@@ -54,19 +64,19 @@ public class Vala.SwitchLabel : CodeNode {
        public SwitchLabel.with_default (SourceReference? source = null) {
                source_reference = source;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_switch_label (this);
        }
-
+       
        public override void accept_children (CodeVisitor visitor) {
                if (expression != null) {
                        expression.accept (visitor);
-
+                       
                        visitor.visit_end_full_expression (expression);
                }
        }
-
+       
        public override bool check (CodeContext context) {
                if (expression != null) {
                        var switch_statement = (SwitchStatement) section.parent_node;
diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala
index 156740f..0e8395d 100644
--- a/vala/valaswitchsection.vala
+++ b/vala/valaswitchsection.vala
@@ -37,7 +37,7 @@ public class Vala.SwitchSection : Block {
        public SwitchSection (SourceReference? source_reference) {
                base (source_reference);
        }
-
+       
        /**
         * Appends the specified label to the list of switch labels.
         *
@@ -49,9 +49,9 @@ public class Vala.SwitchSection : Block {
                }
 
                labels.add (label);
-               label.section = this;
+               label.parent_node = this;
        }
-
+       
        /**
         * Returns a copy of the list of switch labels.
         *
@@ -60,17 +60,17 @@ public class Vala.SwitchSection : Block {
        public List<SwitchLabel> get_labels () {
                return labels;
        }
-
+       
        public bool has_default_label () {
                foreach (SwitchLabel label in labels) {
                        if (label.expression == null) {
                                return true;
                        }
                }
-
+               
                return false;
        }
-
+       
        public override void accept (CodeVisitor visitor) {
                visitor.visit_switch_section (this);
        }
@@ -92,17 +92,12 @@ public class Vala.SwitchSection : Block {
 
                checked = true;
 
+               owner = context.analyzer.get_current_symbol (parent_node).scope;
+
                foreach (SwitchLabel label in get_labels ()) {
                        label.check (context);
                }
 
-               owner = context.analyzer.current_symbol.scope;
-
-               var old_symbol = context.analyzer.current_symbol;
-               var old_insert_block = context.analyzer.insert_block;
-               context.analyzer.current_symbol = this;
-               context.analyzer.insert_block = this;
-
                foreach (Statement st in get_statements ()) {
                        st.check (context);
                }
@@ -116,9 +111,6 @@ public class Vala.SwitchSection : Block {
                        add_error_types (stmt.get_error_types ());
                }
 
-               context.analyzer.current_symbol = old_symbol;
-               context.analyzer.insert_block = old_insert_block;
-
                return !error;
        }
 
diff --git a/vala/valaunlockstatement.vala b/vala/valaunlockstatement.vala
index ff2f401..c9f8ff7 100644
--- a/vala/valaunlockstatement.vala
+++ b/vala/valaunlockstatement.vala
@@ -58,7 +58,7 @@ public class Vala.UnlockStatement : CodeNode, Statement {
                }
 
                /* parent symbol must be the current class */
-               if (resource.symbol_reference.parent_symbol != context.analyzer.current_class) {
+               if (resource.symbol_reference.parent_symbol != context.analyzer.get_current_class (this)) {
                        error = true;
                        resource.error = true;
                        Report.error (resource.source_reference, "Only members of the current class are 
lockable");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]