[vala/wip/transform: 2/47] Make the semantic analyzer be stateless



commit 691e9b1ca41f7363d99cc4b194c1935ca468bd66
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               |   15 +-
 vala/valabaseaccess.vala               |   17 ++-
 vala/valabinaryexpression.vala         |   12 +-
 vala/valablock.vala                    |   12 +-
 vala/valacatchclause.vala              |    1 -
 vala/valaclass.vala                    |   67 +++++++--
 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/valaerrorcode.vala                |   12 ++-
 vala/valafield.vala                    |   11 --
 vala/valaforeachstatement.vala         |   10 +-
 vala/valainterface.vala                |   11 --
 vala/valalambdaexpression.vala         |    8 +-
 vala/valalocalvariable.vala            |    4 +-
 vala/valalockstatement.vala            |   25 +++-
 vala/valamemberaccess.vala             |   39 +++---
 vala/valamethod.vala                   |   13 +--
 vala/valamethodcall.vala               |   25 ++--
 vala/valaobjectcreationexpression.vala |   25 ++-
 vala/valaparameter.vala                |   11 --
 vala/valaproperty.vala                 |   11 --
 vala/valapropertyaccessor.vala         |    6 -
 vala/valareturnstatement.vala          |   22 ++--
 vala/valasemanticanalyzer.vala         |  253 ++++++++++++++------------------
 vala/valastruct.vala                   |   11 --
 vala/valasubroutine.vala               |    2 +-
 vala/valaswitchlabel.vala              |   14 ++-
 vala/valaswitchsection.vala            |   14 +--
 vala/valaunlockstatement.vala          |    2 +-
 vala/valayieldstatement.vala           |    2 +-
 35 files changed, 315 insertions(+), 418 deletions(-)
---
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index 87281ad..7d2064e 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -104,20 +104,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);
@@ -146,7 +148,7 @@ public class Vala.Assignment : Expression {
 			var ma = (MemberAccess) left;
 
 			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;
@@ -305,15 +307,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 8058540..4d7caed 100644
--- a/vala/valabaseaccess.vala
+++ b/vala/valabaseaccess.vala
@@ -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 a73708a..415bde2 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -148,9 +148,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
@@ -175,8 +177,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);
 
@@ -209,8 +211,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);
 
 			decl.check (context);
 
diff --git a/vala/valablock.vala b/vala/valablock.vala
index de8a62a..0daff83 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);
 	}
 
 	/**
@@ -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 a65d749..119cee0 100644
--- a/vala/valacatchclause.vala
+++ b/vala/valacatchclause.vala
@@ -120,7 +120,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 87a0441..ef30093 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -156,17 +156,41 @@ public class Vala.Class : ObjectTypeSymbol {
 	/**
 	 * 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.
@@ -176,6 +200,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);
 				}
@@ -188,12 +213,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.
@@ -204,7 +245,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.
@@ -630,14 +676,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;
@@ -878,9 +916,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 b86ee1f..0d1a945 100644
--- a/vala/valaconditionalexpression.vala
+++ b/vala/valaconditionalexpression.vala
@@ -107,7 +107,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;
@@ -136,8 +136,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 53b84c6..eed0ded 100644
--- a/vala/valaconstant.vala
+++ b/vala/valaconstant.vala
@@ -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 826a0db..c8fb157 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;
-
 		foreach (Parameter param in get_parameters()) {
 			param.check (context);
 		}
@@ -125,40 +117,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 d949c61..71de1aa 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -296,12 +296,6 @@ public class Vala.Delegate : TypeSymbol {
 
 		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);
 		}
@@ -316,8 +310,6 @@ public class Vala.Delegate : TypeSymbol {
 			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 eeabda9..83fa7df 100644
--- a/vala/valaenum.vala
+++ b/vala/valaenum.vala
@@ -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;
-
 		foreach (EnumValue value in values) {
 			value.check (context);
 		}
@@ -183,9 +175,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 aa97641..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.
diff --git a/vala/valafield.vala b/vala/valafield.vala
index 8b932a5..87b197f 100644
--- a/vala/valafield.vala
+++ b/vala/valafield.vala
@@ -100,14 +100,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");
@@ -168,9 +160,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 319968a..68df1d6 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -153,6 +153,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
@@ -352,16 +354,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);
@@ -372,8 +368,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 548304f..16e6b99 100644
--- a/vala/valainterface.vala
+++ b/vala/valainterface.vala
@@ -356,14 +356,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)) {
@@ -445,9 +437,6 @@ public class Vala.Interface : ObjectTypeSymbol {
 			d.check (context);
 		}
 
-		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 027beaf..2c9f066 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -140,10 +140,10 @@ public class Vala.LambdaExpression : Expression {
 		method.check_deprecated (source_reference);
 		method.check_experimental (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;
@@ -162,7 +162,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;
 
 		if (!(method.return_type is VoidType) && CodeContext.get ().profile == Profile.DOVA) {
 			method.result_var = new LocalVariable (method.return_type.copy (), "result", null, source_reference);
@@ -225,7 +225,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 4fd8daf..3019be0 100644
--- a/vala/valalocalvariable.vala
+++ b/vala/valalocalvariable.vala
@@ -171,11 +171,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 e0d4216..b94e88c 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -36,13 +36,30 @@ 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;
@@ -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 64d2b51..c1557e2 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -216,20 +216,20 @@ public class Vala.MemberAccess : Expression {
 			symbol_reference = context.analyzer.root_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) {
@@ -457,13 +457,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) {
@@ -481,10 +483,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) {
@@ -502,10 +504,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) {
@@ -537,7 +539,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) {
@@ -555,14 +557,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;
 				}
@@ -671,7 +670,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
@@ -695,7 +694,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 c2de41d..9edb525 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -621,14 +621,6 @@ public class Vala.Method : Subroutine {
 			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");
@@ -685,7 +677,7 @@ public class Vala.Method : Subroutine {
 			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 ()));
@@ -699,9 +691,6 @@ public class Vala.Method : Subroutine {
 			return false;
 		}
 
-		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 4fdcbc1..6030b39 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -210,7 +210,7 @@ public class Vala.MethodCall : Expression {
 
 		if (mtype is ObjectType || (context.profile == Profile.GOBJECT && call.symbol_reference == context.analyzer.object_type)) {
 			// constructor chain-up
-			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");
@@ -261,7 +261,7 @@ public class Vala.MethodCall : Expression {
 			}
 
 			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) {
 					if (cm.chain_up) {
 						error = true;
@@ -284,7 +284,7 @@ public class Vala.MethodCall : Expression {
 		} else if (call is MemberAccess
 		           && call.symbol_reference is CreationMethod) {
 			// constructor chain-up
-			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, "use `new' operator to create new objects");
@@ -576,11 +576,12 @@ 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");
 				}
-				context.analyzer.current_method.yield_count++;
+				current_method.yield_count++;
 			}
 			if (m != null && m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end") {
 				// .begin call of async method, no error can happen here
@@ -715,7 +716,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)) {
 				if (context.profile != Profile.DOVA) {
 					// can't handle errors in field initializers
 					Report.error (source_reference, "Field initializers must not throw errors");
@@ -729,7 +730,7 @@ public class Vala.MethodCall : Expression {
 				local.floating = true;
 				var decl = new DeclarationStatement (local, source_reference);
 
-				insert_statement (context.analyzer.insert_block, decl);
+				insert_statement (context.analyzer.get_insert_block (this), decl);
 
 				Expression temp_access = new MemberAccess.simple (local.name, source_reference);
 				temp_access.target_type = target_type;
@@ -738,12 +739,12 @@ public class Vala.MethodCall : Expression {
 				local.initializer = this;
 				decl.check (context);
 
-				// 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;
+				// move temp variable to insert block to ensure
+				// variable is in the same block as the declarat
+				// otherwise there will be scoping issues in the
+				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 dfb8ca2..9a18774 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 struct_creation { get; set; }
 
@@ -50,6 +56,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.
@@ -260,7 +267,7 @@ public class Vala.ObjectCreationExpression : Expression {
 
 			if (symbol_reference != null && symbol_reference.access == SymbolAccessibility.PRIVATE) {
 				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;
@@ -392,7 +399,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)) {
 				if (context.profile != Profile.DOVA) {
 					// can't handle errors in field initializers
 					Report.error (source_reference, "Field initializers must not throw errors");
@@ -406,7 +413,7 @@ public class Vala.ObjectCreationExpression : Expression {
 				local.floating = true;
 				var decl = new DeclarationStatement (local, source_reference);
 
-				insert_statement (context.analyzer.insert_block, decl);
+				insert_statement (context.analyzer.get_insert_block (this), decl);
 
 				Expression temp_access = new MemberAccess.simple (local.name, source_reference);
 				temp_access.target_type = target_type;
@@ -415,12 +422,12 @@ public class Vala.ObjectCreationExpression : Expression {
 				local.initializer = this;
 				decl.check (context);
 
-				// 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;
+				// move temp variable to insert block to ensure
+				// variable is in the same block as the declarat
+				// otherwise there will be scoping issues in the
+				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 22fe0c8..d31c720 100644
--- a/vala/valaparameter.vala
+++ b/vala/valaparameter.vala
@@ -115,14 +115,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;
@@ -169,9 +161,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 08b17bb..e9bada7 100644
--- a/vala/valaproperty.vala
+++ b/vala/valaproperty.vala
@@ -363,14 +363,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");
@@ -417,9 +409,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 47a1977..1f6769b 100644
--- a/vala/valapropertyaccessor.vala
+++ b/vala/valapropertyaccessor.vala
@@ -126,10 +126,6 @@ public class Vala.PropertyAccessor : Subroutine {
 			return false;
 		}
 
-		var old_symbol = context.analyzer.current_symbol;
-
-		context.analyzer.current_symbol = this;
-
 		if (prop.source_type == SourceFileType.SOURCE) {
 			if (body == null && !prop.interface_only && !prop.is_abstract) {
 				/* no accessor body specified, insert default body */
@@ -182,8 +178,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 6a53705..ee14a71 100644
--- a/vala/valareturnstatement.vala
+++ b/vala/valareturnstatement.vala
@@ -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,7 +89,7 @@ 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;
@@ -99,14 +101,14 @@ public class Vala.ReturnStatement : CodeNode, Statement {
 		}
 
 		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;
 		}
@@ -117,14 +119,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;
@@ -132,15 +134,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 bd4f4fb..ad30589 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -31,107 +31,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 	public CodeContext context { get; set; }
 
 	public Symbol root_symbol;
-	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;
@@ -233,17 +132,120 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 			error_type = new ObjectType ((Class) dova_ns.scope.lookup ("Error"));
 		}
 
-		current_symbol = root_symbol;
 		context.root.check (context);
 		context.accept (this);
 	}
 
 	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);
@@ -760,8 +762,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;
@@ -862,39 +864,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;
@@ -904,8 +875,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 f913a01..cdcf2a0 100644
--- a/vala/valastruct.vala
+++ b/vala/valastruct.vala
@@ -487,14 +487,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);
 
@@ -552,9 +544,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 73cab98..0ef8bf3 100644
--- a/vala/valasubroutine.vala
+++ b/vala/valasubroutine.vala
@@ -45,7 +45,7 @@ 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 9468b0e..d6e5541 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.
diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala
index ce81805..b79e39e 100644
--- a/vala/valaswitchsection.vala
+++ b/vala/valaswitchsection.vala
@@ -45,7 +45,7 @@ public class Vala.SwitchSection : Block {
 	 */
 	public void add_label (SwitchLabel label) {
 		labels.add (label);
-		label.section = this;
+		label.parent_node = this;
 	}
 	
 	/**
@@ -88,17 +88,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);
 		}
@@ -112,9 +107,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");
diff --git a/vala/valayieldstatement.vala b/vala/valayieldstatement.vala
index 8b2069f..084ae26 100644
--- a/vala/valayieldstatement.vala
+++ b/vala/valayieldstatement.vala
@@ -75,7 +75,7 @@ public class Vala.YieldStatement : CodeNode, Statement {
 			error = yield_expression.error;
 		}
 
-		context.analyzer.current_method.yield_count++;
+		context.analyzer.get_current_method (this).yield_count++;
 
 		return !error;
 	}



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