[vala/staging] vala: Make SemanticAnalyzer be stateless



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

    vala: Make SemanticAnalyzer be stateless

 vala/valaassignment.vala               |  15 +-
 vala/valabaseaccess.vala               |  25 +--
 vala/valabinaryexpression.vala         |  12 +-
 vala/valablock.vala                    |  12 +-
 vala/valacatchclause.vala              |   1 -
 vala/valaclass.vala                    |  11 --
 vala/valaconditionalexpression.vala    |   6 +-
 vala/valaconstant.vala                 |  14 --
 vala/valaconstructor.vala              |   7 +-
 vala/valacreationmethod.vala           |  27 +---
 vala/valadelegate.vala                 |   8 -
 vala/valadestructor.vala               |   5 -
 vala/valaenum.vala                     |  11 --
 vala/valafield.vala                    |  11 --
 vala/valaforeachstatement.vala         |  10 +-
 vala/valainterface.vala                |  11 --
 vala/valalambdaexpression.vala         |   8 +-
 vala/valalocalvariable.vala            |  19 +--
 vala/valalockstatement.vala            |   4 +-
 vala/valamemberaccess.vala             |  41 +++--
 vala/valamethod.vala                   |  13 +-
 vala/valamethodcall.vala               |  13 +-
 vala/valaobjectcreationexpression.vala |  13 +-
 vala/valaparameter.vala                |  11 --
 vala/valaproperty.vala                 |  11 --
 vala/valapropertyaccessor.vala         |   6 -
 vala/valareturnstatement.vala          |  22 +--
 vala/valasemanticanalyzer.vala         | 271 ++++++++++++++++-----------------
 vala/valastruct.vala                   |  11 --
 vala/valasubroutine.vala               |   1 -
 vala/valaswitchsection.vala            |  12 +-
 vala/valaunlockstatement.vala          |   4 +-
 vala/valayieldstatement.vala           |   3 +-
 33 files changed, 238 insertions(+), 411 deletions(-)
---
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index 9db0ec163..52ef6ae3b 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -117,19 +117,21 @@ 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);
-                       insert_statement (context.analyzer.insert_block, decl);
+                       insert_statement (insert_block, decl);
                        decl.check (context);
 
                        int i = 0;
                        ExpressionStatement stmt = null;
                        foreach (var expr in tuple.get_expressions ()) {
                                if (stmt != null) {
-                                       insert_statement (context.analyzer.insert_block, stmt);
+                                       insert_statement (insert_block, stmt);
                                        stmt.check (context);
                                }
 
@@ -165,7 +167,7 @@ public class Vala.Assignment : Expression {
                        }
 
                        if ((!(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;
@@ -273,15 +275,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;
diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala
index 955233bdc..613990e0f 100644
--- a/vala/valabaseaccess.vala
+++ b/vala/valabaseaccess.vala
@@ -56,38 +56,43 @@ 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);
+               var current_method = context.analyzer.get_current_method (this);
+               var current_property_accessor = context.analyzer.get_current_property_accessor (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 if (context.analyzer.current_class.is_compact && context.analyzer.current_method != 
null
-                   && !(context.analyzer.current_method is CreationMethod)) {
+               } else if (current_class.is_compact && current_method != null
+                   && !(current_method is CreationMethod)) {
                        error = true;
                        Report.error (source_reference, "Base access invalid in virtual overridden method of 
compact class");
                        return false;
-               } else if (context.analyzer.current_class.is_compact && 
context.analyzer.current_property_accessor != null) {
+               } else if (current_class.is_compact && current_property_accessor != null) {
                        error = true;
                        Report.error (source_reference, "Base access invalid in virtual overridden property 
of compact 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 f21aa42c0..42d291ecd 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -140,9 +140,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_non_local_symbol (this) is Block
                    && (operator == BinaryOperator.AND || operator == BinaryOperator.OR)) {
                        // convert conditional expression into if statement
                        // required for flow analysis and exception handling
@@ -167,8 +169,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);
 
@@ -242,8 +244,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 7419b5b9d..72e7801e2 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -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);
        }
 
        /**
@@ -151,12 +153,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_non_local_symbol (parent_node).scope;
 
                for (int i = 0; i < statement_list.size; i++) {
                        statement_list[i].check (context);
@@ -170,9 +167,6 @@ public class Vala.Block : Symbol, Statement {
                        constant.active = false;
                }
 
-               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 1ff942116..8c0b32538 100644
--- a/vala/valacatchclause.vala
+++ b/vala/valacatchclause.vala
@@ -131,7 +131,6 @@ public class Vala.CatchClause : CodeNode {
                        if (variable_name != null) {
                                error_variable = new LocalVariable (error_type.copy (), variable_name, null, 
source_reference);
 
-                               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 933a67c26..b51bf3912 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -532,14 +532,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;
@@ -829,9 +821,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 3395dd56f..b6884f616 100644
--- a/vala/valaconditionalexpression.vala
+++ b/vala/valaconditionalexpression.vala
@@ -145,7 +145,7 @@ public class Vala.ConditionalExpression : Expression {
 
                checked = true;
 
-               if (!(context.analyzer.current_symbol is Block)) {
+               if (!(context.analyzer.get_current_non_local_symbol (this) is Block)) {
                        Report.error (source_reference, "Conditional expressions may only be used in blocks");
                        error = true;
                        return false;
@@ -174,8 +174,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 0a9266cf1..bf6635e18 100644
--- a/vala/valaconstant.vala
+++ b/vala/valaconstant.vala
@@ -102,17 +102,6 @@ public class Vala.Constant : Symbol {
 
                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)) {
@@ -171,9 +160,6 @@ public class Vala.Constant : Symbol {
                        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 ae8f19e8d..86f24de3f 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);
                }
@@ -85,8 +82,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 ae8daab38..e201624a9 100644
--- a/vala/valacreationmethod.vala
+++ b/vala/valacreationmethod.vala
@@ -88,19 +88,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 (parent_node).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);
@@ -135,40 +127,23 @@ public class Vala.CreationMethod : Method {
                                if (context.profile == Profile.GOBJECT
                                    && 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 4b4e7074a..039f6a5c6 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -293,12 +293,6 @@ 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);
                }
@@ -315,8 +309,6 @@ public class Vala.Delegate : TypeSymbol, Callable {
                        }
                }
 
-               context.analyzer.current_source_file = old_source_file;
-
                return !error;
        }
 }
diff --git a/vala/valadestructor.vala b/vala/valadestructor.vala
index 7ee3843bd..ddfb0f9ea 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 508ef12ef..15cb2c830 100644
--- a/vala/valaenum.vala
+++ b/vala/valaenum.vala
@@ -158,14 +158,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;
@@ -184,9 +176,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/valafield.vala b/vala/valafield.vala
index 6bd54ff95..fd2082d71 100644
--- a/vala/valafield.vala
+++ b/vala/valafield.vala
@@ -84,14 +84,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");
@@ -189,9 +181,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 67063bbe1..ada291ccd 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -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
@@ -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 f6c503641..61d1e50ef 100644
--- a/vala/valainterface.vala
+++ b/vala/valainterface.vala
@@ -194,14 +194,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)) {
@@ -364,9 +356,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 a22497e70..5e8fcee07 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -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_non_local_symbol (this).scope;
 
                var lambda_params = get_parameters ();
                Iterator<Parameter> lambda_param_it = lambda_params.iterator ();
@@ -220,7 +220,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 3a2ecae01..acc6a3607 100644
--- a/vala/valalocalvariable.vala
+++ b/vala/valalocalvariable.vala
@@ -92,6 +92,16 @@ public class Vala.LocalVariable : Variable {
                        }
                }
 
+               // current_symbol is a Method if this is the `result'
+               // variable used for postconditions
+               var block = context.analyzer.get_current_block (this);
+               if (block != null) {
+                       /* so that we can use parent_symbol */
+                       block.add_local_variable (this);
+               }
+
+               active = false;
+
                if (variable_type != null) {
                        if (variable_type is VoidType) {
                                error = true;
@@ -211,15 +221,6 @@ 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;
-               if (block != null) {
-                       block.add_local_variable (this);
-               }
-
                active = true;
 
                return !error;
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
index e64d4a206..be942acee 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -114,7 +114,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");
@@ -122,7 +122,7 @@ public class Vala.LockStatement : CodeNode, Statement {
                }
 
                /* parent class must not be compact */
-               if (context.analyzer.current_class.is_compact) {
+               if (context.analyzer.get_current_class (this).is_compact) {
                        error = true;
                        resource.error = true;
                        Report.error (resource.source_reference, "Only members of the non-compact classes are 
lockable");
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 37eeafb87..70bf044cf 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -226,20 +226,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_non_local_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) {
@@ -484,13 +484,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) {
@@ -508,10 +510,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) {
@@ -529,10 +531,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) {
@@ -561,7 +563,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;
@@ -571,7 +573,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) {
@@ -589,14 +591,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_non_local_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_non_local_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 bfaf2a00b..7bcdfdfdf 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -771,14 +771,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.floating_reference = returns_floating_reference;
                return_type.check (context);
 
@@ -867,7 +859,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 ()));
@@ -895,9 +887,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 c1b034fa3..1b0916349 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -258,7 +258,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");
@@ -518,7 +518,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");
                                }
@@ -654,7 +655,7 @@ public class Vala.MethodCall : Expression {
                if (tree_can_fail) {
                        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_non_local_symbol (this) is Block)) {
                                // can't handle errors in field initializers
                                Report.error (source_reference, "Field initializers must not throw errors");
                        } else {
@@ -664,7 +665,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);
 
@@ -675,9 +676,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 5f4fce753..86ab41a36 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -293,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_non_local_symbol 
(this); this_symbol != null; this_symbol = this_symbol.parent_symbol) {
                                        if (this_symbol == cl) {
                                                in_target_type = true;
                                                break;
@@ -361,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");
                                }
@@ -493,7 +494,7 @@ public class Vala.ObjectCreationExpression : Expression {
                if (tree_can_fail) {
                        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_non_local_symbol (this) is Block)) {
                                // can't handle errors in field initializers
                                Report.error (source_reference, "Field initializers must not throw errors");
                        } else {
@@ -503,7 +504,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
@@ -513,9 +514,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 7c13a7c19..3c8bb0f09 100644
--- a/vala/valaparameter.vala
+++ b/vala/valaparameter.vala
@@ -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;
@@ -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 cd1bcaff5..c4ab84c44 100644
--- a/vala/valaproperty.vala
+++ b/vala/valaproperty.vala
@@ -450,14 +450,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");
@@ -514,9 +506,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 e348c2510..019e993df 100644
--- a/vala/valapropertyaccessor.vala
+++ b/vala/valapropertyaccessor.vala
@@ -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);
                }
@@ -206,8 +202,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 f51164968..e4fa6b506 100644
--- a/vala/valareturnstatement.vala
+++ b/vala/valareturnstatement.vala
@@ -83,8 +83,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.copy ();
+                       return_expression.target_type = current_return_type.copy ();
                }
 
                if (return_expression != null && !return_expression.check (context)) {
@@ -93,21 +95,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;
                }
@@ -118,14 +120,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;
@@ -133,15 +135,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 ()));
                }
 
                return !error;
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 485ab222d..1f4df2cb8 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;
@@ -164,7 +62,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
        // keep replaced alive to make sure they remain valid
        // for the whole execution of CodeNode.accept
-       public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
+       public Set<CodeNode> replaced_nodes = new HashSet<CodeNode> (direct_hash, direct_equal);
 
        public SemanticAnalyzer () {
        }
@@ -219,7 +117,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);
 
@@ -227,11 +124,130 @@ 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 != null && !(node is Symbol)) {
+                       node = node.parent_node;
+               }
+               return (Symbol) node;
+       }
+
+       public unowned Symbol? get_current_non_local_symbol (CodeNode node) {
+               while (node != null && (!(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 || (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 Namespace? get_current_namespace (CodeNode node) {
+               unowned Symbol sym = get_current_symbol (node);
+               while (sym != null && !(sym is Namespace)) {
+                       sym = sym.parent_symbol;
+               }
+               return (Namespace) 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 != null && !(sym is Method)) {
+                       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 != null && !(sym is PropertyAccessor)) {
+                       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 != null && !(sym is Method) && !(sym is PropertyAccessor)) {
+                       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) {
+               while (node != null && !(node is Block)) {
+                       node = node.parent_node;
+               }
+               return (Block) node;
+       }
+
+       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);
@@ -903,8 +919,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;
@@ -1021,39 +1037,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;
@@ -1063,8 +1048,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 c96632805..e47bc3f24 100644
--- a/vala/valastruct.vala
+++ b/vala/valastruct.vala
@@ -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);
 
@@ -564,9 +556,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 e9c05ac23..0ef8bf333 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/valaswitchsection.vala b/vala/valaswitchsection.vala
index 2b6bc60ab..9e94edea1 100644
--- a/vala/valaswitchsection.vala
+++ b/vala/valaswitchsection.vala
@@ -99,17 +99,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);
                }
@@ -118,9 +113,6 @@ public class Vala.SwitchSection : Block {
                        local.active = false;
                }
 
-               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 d60d5706c..e97458ea8 100644
--- a/vala/valaunlockstatement.vala
+++ b/vala/valaunlockstatement.vala
@@ -72,7 +72,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");
@@ -80,7 +80,7 @@ public class Vala.UnlockStatement : CodeNode, Statement {
                }
 
                /* parent class must not be compact */
-               if (context.analyzer.current_class.is_compact) {
+               if (context.analyzer.get_current_class (this).is_compact) {
                        error = true;
                        resource.error = true;
                        Report.error (resource.source_reference, "Only members of the non-compact classes are 
lockable");
diff --git a/vala/valayieldstatement.vala b/vala/valayieldstatement.vala
index 91d8e7f9f..2e9838e92 100644
--- a/vala/valayieldstatement.vala
+++ b/vala/valayieldstatement.vala
@@ -42,7 +42,8 @@ public class Vala.YieldStatement : CodeNode, Statement {
 
                checked = true;
 
-               if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) {
+               unowned Method? current_method = context.analyzer.get_current_method (this);
+               if (current_method == null || !current_method.coroutine) {
                        error = true;
                        Report.error (source_reference, "yield statement not available outside async method");
                }


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