From: Luca Bruno Date: Wed, 1 Jun 2011 08:18:44 +0000 (+0200) Subject: Enable flow analysis for out parameters X-Git-Tag: 0.13.2~148 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=43570fcee9d6965690b9c612b7c886cb85ad107f;p=thirdparty%2Fvala.git Enable flow analysis for out parameters Fixes bug 638363. --- diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala index 3b8857a11..d88c3e073 100644 --- a/vala/valaassignment.vala +++ b/vala/valaassignment.vala @@ -536,16 +536,19 @@ public class Vala.Assignment : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { right.get_defined_variables (collection); left.get_defined_variables (collection); var local = left.symbol_reference as LocalVariable; + var param = left.symbol_reference as Parameter; if (local != null) { collection.add (local); + } else if (param != null && param.direction == ParameterDirection.OUT) { + collection.add (param); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { var ma = left as MemberAccess; var ea = left as ElementAccess; if (ma != null && ma.inner != null) { diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 50d49488c..07b3ee386 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -507,12 +507,12 @@ public class Vala.BinaryExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { left.get_defined_variables (collection); right.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { left.get_used_variables (collection); right.get_used_variables (collection); } diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala index ca5f2a1be..40ed1ce3f 100644 --- a/vala/valacastexpression.vala +++ b/vala/valacastexpression.vala @@ -165,11 +165,11 @@ public class Vala.CastExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala index 46b4e0fa2..a65d74997 100644 --- a/vala/valacatchclause.vala +++ b/vala/valacatchclause.vala @@ -149,7 +149,7 @@ public class Vala.CatchClause : CodeNode { codegen.visit_catch_clause (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { if (error_variable != null) { collection.add (error_variable); } diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala index b1fc30efa..b5f637ca7 100644 --- a/vala/valacodenode.vala +++ b/vala/valacodenode.vala @@ -168,10 +168,10 @@ public abstract class Vala.CodeNode { return str.append (" */").str; } - public virtual void get_defined_variables (Collection collection) { + public virtual void get_defined_variables (Collection collection) { } - public virtual void get_used_variables (Collection collection) { + public virtual void get_used_variables (Collection collection) { } public static string get_temp_name () { diff --git a/vala/valadeclarationstatement.vala b/vala/valadeclarationstatement.vala index 9eb8fffd6..c4c778f21 100644 --- a/vala/valadeclarationstatement.vala +++ b/vala/valadeclarationstatement.vala @@ -89,7 +89,7 @@ public class Vala.DeclarationStatement : CodeNode, Statement { codegen.visit_declaration_statement (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { var local = declaration as LocalVariable; if (local != null) { var array_type = local.variable_type as ArrayType; @@ -102,7 +102,7 @@ public class Vala.DeclarationStatement : CodeNode, Statement { } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { var local = declaration as LocalVariable; if (local != null && local.initializer != null) { local.initializer.get_used_variables (collection); diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala index d8c769997..c81f3b30d 100644 --- a/vala/valaelementaccess.vala +++ b/vala/valaelementaccess.vala @@ -238,14 +238,14 @@ public class Vala.ElementAccess : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { container.get_defined_variables (collection); foreach (Expression index in indices) { index.get_defined_variables (collection); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { container.get_used_variables (collection); foreach (Expression index in indices) { index.get_used_variables (collection); diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala index afca3775e..6d01a985b 100644 --- a/vala/valaexpressionstatement.vala +++ b/vala/valaexpressionstatement.vala @@ -91,11 +91,11 @@ public class Vala.ExpressionStatement : CodeNode, Statement { codegen.visit_expression_statement (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { expression.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { expression.get_used_variables (collection); } } diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index c17b77b6c..87d6728f9 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -90,9 +90,9 @@ public class Vala.FlowAnalyzer : CodeVisitor { private bool unreachable_reported; private List jump_stack = new ArrayList (); - Map> var_map; - Set used_vars; - Map phi_functions; + Map> var_map; + Set used_vars; + Map phi_functions; public FlowAnalyzer () { } @@ -199,6 +199,16 @@ public class Vala.FlowAnalyzer : CodeVisitor { result_ma.symbol_reference = m.result_var; m.return_block.add_node (result_ma); } + if (m is Method) { + // ensure out parameters are defined at end of method + foreach (var param in ((Method) m).get_parameters ()) { + if (param.direction == ParameterDirection.OUT) { + var param_ma = new MemberAccess.simple (param.name, param.source_reference); + param_ma.symbol_reference = param; + m.return_block.add_node (param_ma); + } + } + } current_block = new BasicBlock (); m.entry_block.connect (current_block); @@ -330,19 +340,19 @@ public class Vala.FlowAnalyzer : CodeVisitor { } } - Map> get_assignment_map (List block_list, BasicBlock entry_block) { - var map = new HashMap> (); + Map> get_assignment_map (List block_list, BasicBlock entry_block) { + var map = new HashMap> (); foreach (BasicBlock block in block_list) { - var defined_variables = new ArrayList (); + var defined_variables = new ArrayList (); foreach (CodeNode node in block.get_nodes ()) { node.get_defined_variables (defined_variables); } - foreach (LocalVariable local in defined_variables) { - var block_set = map.get (local); + foreach (Variable variable in defined_variables) { + var block_set = map.get (variable); if (block_set == null) { block_set = new HashSet (); - map.set (local, block_set); + map.set (variable, block_set); } block_set.add (block); } @@ -363,9 +373,9 @@ public class Vala.FlowAnalyzer : CodeVisitor { phi.set (block, 0); } - foreach (LocalVariable local in assign.get_keys ()) { + foreach (Variable variable in assign.get_keys ()) { counter++; - foreach (BasicBlock block in assign.get (local)) { + foreach (BasicBlock block in assign.get (variable)) { work_list.add (block); added.set (block, counter); } @@ -375,7 +385,7 @@ public class Vala.FlowAnalyzer : CodeVisitor { foreach (BasicBlock frontier in block.get_dominator_frontier ()) { int blockPhi = phi.get (frontier); if (blockPhi < counter) { - frontier.add_phi_function (new PhiFunction (local, frontier.get_predecessors ().size)); + frontier.add_phi_function (new PhiFunction (variable, frontier.get_predecessors ().size)); phi.set (frontier, counter); int block_added = added.get (frontier); if (block_added < counter) { @@ -389,32 +399,37 @@ public class Vala.FlowAnalyzer : CodeVisitor { } void check_variables (BasicBlock entry_block) { - var_map = new HashMap>(); - used_vars = new HashSet (); - phi_functions = new HashMap (); + var_map = new HashMap>(); + used_vars = new HashSet (); + phi_functions = new HashMap (); check_block_variables (entry_block); // check for variables used before initialization - var used_vars_queue = new ArrayList (); - foreach (LocalVariable local in used_vars) { - used_vars_queue.add (local); + var used_vars_queue = new ArrayList (); + foreach (Variable variable in used_vars) { + used_vars_queue.add (variable); } while (used_vars_queue.size > 0) { - LocalVariable used_var = used_vars_queue[0]; + Variable used_var = used_vars_queue[0]; used_vars_queue.remove_at (0); PhiFunction phi = phi_functions.get (used_var); if (phi != null) { - foreach (LocalVariable local in phi.operands) { - if (local == null) { - Report.error (used_var.source_reference, "use of possibly unassigned local variable `%s'".printf (used_var.name)); + foreach (Variable variable in phi.operands) { + if (variable == null) { + if (used_var is LocalVariable) { + Report.error (used_var.source_reference, "use of possibly unassigned local variable `%s'".printf (used_var.name)); + } else { + // parameter + Report.warning (used_var.source_reference, "use of possibly unassigned parameter `%s'".printf (used_var.name)); + } continue; } - if (!(local in used_vars)) { - local.source_reference = used_var.source_reference; - used_vars.add (local); - used_vars_queue.add (local); + if (!(variable in used_vars)) { + variable.source_reference = used_var.source_reference; + used_vars.add (variable); + used_vars_queue.add (variable); } } } @@ -423,33 +438,38 @@ public class Vala.FlowAnalyzer : CodeVisitor { void check_block_variables (BasicBlock block) { foreach (PhiFunction phi in block.get_phi_functions ()) { - LocalVariable versioned_var = process_assignment (var_map, phi.original_variable); + Variable versioned_var = process_assignment (var_map, phi.original_variable); phi_functions.set (versioned_var, phi); } foreach (CodeNode node in block.get_nodes ()) { - var used_variables = new ArrayList (); + var used_variables = new ArrayList (); node.get_used_variables (used_variables); - foreach (LocalVariable var_symbol in used_variables) { + foreach (Variable var_symbol in used_variables) { var variable_stack = var_map.get (var_symbol); if (variable_stack == null || variable_stack.size == 0) { - Report.error (node.source_reference, "use of possibly unassigned local variable `%s'".printf (var_symbol.name)); + if (var_symbol is LocalVariable) { + Report.error (node.source_reference, "use of possibly unassigned local variable `%s'".printf (var_symbol.name)); + } else { + // parameter + Report.warning (node.source_reference, "use of possibly unassigned parameter `%s'".printf (var_symbol.name)); + } continue; } - var versioned_local = variable_stack.get (variable_stack.size - 1); - if (!(versioned_local in used_vars)) { - versioned_local.source_reference = node.source_reference; + var versioned_variable = variable_stack.get (variable_stack.size - 1); + if (!(versioned_variable in used_vars)) { + versioned_variable.source_reference = node.source_reference; } - used_vars.add (versioned_local); + used_vars.add (versioned_variable); } - var defined_variables = new ArrayList (); + var defined_variables = new ArrayList (); node.get_defined_variables (defined_variables); - foreach (LocalVariable local in defined_variables) { - process_assignment (var_map, local); + foreach (Variable variable in defined_variables) { + process_assignment (var_map, variable); } } @@ -479,23 +499,29 @@ public class Vala.FlowAnalyzer : CodeVisitor { variable_stack.remove_at (variable_stack.size - 1); } foreach (CodeNode node in block.get_nodes ()) { - var defined_variables = new ArrayList (); + var defined_variables = new ArrayList (); node.get_defined_variables (defined_variables); - foreach (LocalVariable local in defined_variables) { - var variable_stack = var_map.get (local); + foreach (Variable variable in defined_variables) { + var variable_stack = var_map.get (variable); variable_stack.remove_at (variable_stack.size - 1); } } } - LocalVariable process_assignment (Map> var_map, LocalVariable var_symbol) { + Variable process_assignment (Map> var_map, Variable var_symbol) { var variable_stack = var_map.get (var_symbol); if (variable_stack == null) { - variable_stack = new ArrayList (); + variable_stack = new ArrayList (); var_map.set (var_symbol, variable_stack); } - LocalVariable versioned_var = new LocalVariable (var_symbol.variable_type, var_symbol.name, null, var_symbol.source_reference); + Variable versioned_var; + if (var_symbol is LocalVariable) { + versioned_var = new LocalVariable (var_symbol.variable_type, var_symbol.name, null, var_symbol.source_reference); + } else { + // parameter + versioned_var = new Parameter (var_symbol.name, var_symbol.variable_type, var_symbol.source_reference); + } variable_stack.add (versioned_var); return versioned_var; } diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala index a518a2bee..319968af6 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -403,7 +403,7 @@ public class Vala.ForeachStatement : Block { codegen.visit_foreach_statement (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { collection.add (element_variable); } } diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala index ecfe25106..1d791af32 100644 --- a/vala/valalambdaexpression.vala +++ b/vala/valalambdaexpression.vala @@ -255,10 +255,10 @@ public class Vala.LambdaExpression : Expression { codegen.visit_expression (this); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { // require captured variables to be initialized if (method.closure) { - method.get_captured_variables (collection); + method.get_captured_variables ((Collection) collection); } } } diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala index aaa5a1748..1ec08dac3 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -847,19 +847,22 @@ public class Vala.MemberAccess : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { if (inner != null) { inner.get_defined_variables (collection); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { if (inner != null) { inner.get_used_variables (collection); } var local = symbol_reference as LocalVariable; + var param = symbol_reference as Parameter; if (local != null) { collection.add (local); + } else if (param != null && param.direction == ParameterDirection.OUT) { + collection.add (param); } } } diff --git a/vala/valamethod.vala b/vala/valamethod.vala index 39b222302..d1215ab94 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -1164,11 +1164,11 @@ public class Vala.Method : Subroutine { } } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { // capturing variables is only supported if they are initialized // therefore assume that captured variables are initialized if (closure) { - get_captured_variables (collection); + get_captured_variables ((Collection) collection); } } } diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index f794979d9..c60214222 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -791,7 +791,7 @@ public class Vala.MethodCall : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { call.get_defined_variables (collection); foreach (Expression arg in argument_list) { @@ -799,7 +799,7 @@ public class Vala.MethodCall : Expression { } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { call.get_used_variables (collection); foreach (Expression arg in argument_list) { diff --git a/vala/valanamedargument.vala b/vala/valanamedargument.vala index c88e8fce7..4c3e23b33 100644 --- a/vala/valanamedargument.vala +++ b/vala/valanamedargument.vala @@ -89,11 +89,11 @@ public class Vala.NamedArgument : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } } diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index 82e998bf4..1152b460f 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -443,13 +443,13 @@ public class Vala.ObjectCreationExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { foreach (Expression arg in argument_list) { arg.get_defined_variables (collection); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { foreach (Expression arg in argument_list) { arg.get_used_variables (collection); } diff --git a/vala/valaphifunction.vala b/vala/valaphifunction.vala index 081fca082..41187960f 100644 --- a/vala/valaphifunction.vala +++ b/vala/valaphifunction.vala @@ -22,15 +22,15 @@ public class Vala.PhiFunction { - public LocalVariable original_variable { get; private set; } + public Variable original_variable { get; private set; } - public List operands { get; private set; } + public List operands { get; private set; } - public PhiFunction (LocalVariable variable, int num_of_ops) { + public PhiFunction (Variable variable, int num_of_ops) { this.original_variable = variable; - this.operands = new ArrayList (); + this.operands = new ArrayList (); for (int i = 0; i < num_of_ops; i++) { - this.operands.add ((LocalVariable) null); + this.operands.add ((Variable) null); } } } diff --git a/vala/valapointerindirection.vala b/vala/valapointerindirection.vala index 301ca7159..fffbf9358 100644 --- a/vala/valapointerindirection.vala +++ b/vala/valapointerindirection.vala @@ -109,11 +109,11 @@ public class Vala.PointerIndirection : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } } diff --git a/vala/valapostfixexpression.vala b/vala/valapostfixexpression.vala index 9ac0113d0..5f44157b9 100644 --- a/vala/valapostfixexpression.vala +++ b/vala/valapostfixexpression.vala @@ -72,15 +72,18 @@ public class Vala.PostfixExpression : Expression { return false; } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); var local = inner.symbol_reference as LocalVariable; + var param = inner.symbol_reference as Parameter; if (local != null) { collection.add (local); + } else if (param != null && param.direction == ParameterDirection.OUT) { + collection.add (param); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala index 2d82ac060..29c522e55 100644 --- a/vala/valareferencetransferexpression.vala +++ b/vala/valareferencetransferexpression.vala @@ -115,11 +115,11 @@ public class Vala.ReferenceTransferExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { inner.get_used_variables (collection); } } diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala index 39aff8259..6a5370580 100644 --- a/vala/valareturnstatement.vala +++ b/vala/valareturnstatement.vala @@ -158,13 +158,13 @@ public class Vala.ReturnStatement : CodeNode, Statement { codegen.visit_return_statement (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { if (return_expression != null) { return_expression.get_defined_variables (collection); } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { if (return_expression != null) { return_expression.get_used_variables (collection); } diff --git a/vala/valasliceexpression.vala b/vala/valasliceexpression.vala index 4680a1bff..7b741a340 100644 --- a/vala/valasliceexpression.vala +++ b/vala/valasliceexpression.vala @@ -174,13 +174,13 @@ public class Vala.SliceExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { container.get_defined_variables (collection); start.get_defined_variables (collection); stop.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { container.get_used_variables (collection); start.get_used_variables (collection); stop.get_used_variables (collection); diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala index 2667db6aa..2dbcc3de6 100644 --- a/vala/valathrowstatement.vala +++ b/vala/valathrowstatement.vala @@ -123,11 +123,11 @@ public class Vala.ThrowStatement : CodeNode, Statement { codegen.visit_throw_statement (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { error_expression.get_defined_variables (collection); } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { error_expression.get_used_variables (collection); } } diff --git a/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala index a26c3dac4..11c3bb417 100644 --- a/vala/valaunaryexpression.vala +++ b/vala/valaunaryexpression.vala @@ -253,17 +253,21 @@ public class Vala.UnaryExpression : Expression { codegen.visit_expression (this); } - public override void get_defined_variables (Collection collection) { + public override void get_defined_variables (Collection collection) { inner.get_defined_variables (collection); if (operator == UnaryOperator.OUT || operator == UnaryOperator.REF) { var local = inner.symbol_reference as LocalVariable; + var param = inner.symbol_reference as Parameter; if (local != null) { collection.add (local); } + if (param != null && param.direction == ParameterDirection.OUT) { + collection.add (param); + } } } - public override void get_used_variables (Collection collection) { + public override void get_used_variables (Collection collection) { if (operator != UnaryOperator.OUT) { inner.get_used_variables (collection); }