[vala/wip/ricotz/lsp: 9/13] langserver: Handle unresolved symbols robustly.



commit adee6c1d11a1751b2b2302b7642cd809843cb45b
Author: Princeton Ferro <princetonferro gmail com>
Date:   Tue Jan 7 17:27:55 2020 -0500

    langserver: Handle unresolved symbols robustly.
    
    These changes prevent crashes in later compiler stages when there are
    many unresolved symbols.

 vala/valaarraytype.vala        |  6 +++++-
 vala/valabinaryexpression.vala | 13 ++++++++-----
 vala/valaconstant.vala         |  6 +++---
 vala/valaelementaccess.vala    |  4 +++-
 vala/valaflowanalyzer.vala     | 33 ++++++++++++++++++++++++++++-----
 vala/valagirparser.vala        |  6 ++++++
 vala/valalambdaexpression.vala |  4 ++--
 vala/valamemberaccess.vala     |  3 +++
 vala/valamethodcall.vala       |  7 +++++--
 vala/valaparameter.vala        |  4 ++--
 vala/valathrowstatement.vala   |  8 +++++---
 11 files changed, 70 insertions(+), 24 deletions(-)
---
diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala
index bc5eb16d7..24b53c891 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -106,8 +106,12 @@ public class Vala.ArrayType : ReferenceType {
                return null;
        }
 
-       unowned ArrayLengthField get_length_field () {
+       unowned ArrayLengthField? get_length_field () {
                if (length_field == null) {
+                       if (length_type == null) {
+                               return null;
+                       }
+
                        length_field = new ArrayLengthField (source_reference);
 
                        length_field.access = SymbolAccessibility.PUBLIC;
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
index 927ca5413..8396b6947 100644
--- a/vala/valabinaryexpression.vala
+++ b/vala/valabinaryexpression.vala
@@ -330,8 +330,10 @@ public class Vala.BinaryExpression : Expression {
 
                left.target_type = left.value_type.copy ();
                left.target_type.value_owned = false;
-               right.target_type = right.value_type.copy ();
-               right.target_type.value_owned = false;
+               if (right.value_type != null) {
+                       right.target_type = right.value_type.copy ();
+                       right.target_type.value_owned = false;
+               }
 
                if (operator == BinaryOperator.PLUS
                    && left.value_type.type_symbol == context.analyzer.string_type.type_symbol) {
@@ -547,7 +549,8 @@ public class Vala.BinaryExpression : Expression {
                        break;
                case BinaryOperator.IN:
                        if (left.value_type.compatible (context.analyzer.int_type)
-                           && right.value_type.compatible (context.analyzer.int_type)) {
+                                       && right.value_type != null
+                                       && right.value_type.compatible (context.analyzer.int_type)) {
                                // integers or enums
                                left.target_type.nullable = false;
                                right.target_type.nullable = false;
@@ -557,9 +560,9 @@ public class Vala.BinaryExpression : Expression {
                                }
                        } else {
                                // otherwise require a bool contains () method
-                               var contains_method = right.value_type.get_member ("contains") as Method;
+                               var contains_method = (right.value_type != null ? right.value_type.get_member 
("contains") : null) as Method;
                                if (contains_method == null) {
-                                       Report.error (source_reference, "`%s' does not have a `contains' 
method".printf (right.value_type.to_string ()));
+                                       Report.error (source_reference, "`%s' does not have a `contains' 
method".printf (right.value_type != null ? right.value_type.to_string () : "(null)"));
                                        error = true;
                                        return false;
                                }
diff --git a/vala/valaconstant.vala b/vala/valaconstant.vala
index 3ff4bf3c4..80872531f 100644
--- a/vala/valaconstant.vala
+++ b/vala/valaconstant.vala
@@ -115,7 +115,7 @@ public class Vala.Constant : Symbol {
 
                type_reference.check (context);
 
-               if (!check_const_type (type_reference, context)) {
+               if (!Constant.check_const_type (type_reference, context)) {
                        error = true;
                        Report.error (source_reference, "`%s' not supported as type for constants".printf 
(type_reference.to_string ()));
                        return false;
@@ -182,13 +182,13 @@ public class Vala.Constant : Symbol {
                return !error;
        }
 
-       bool check_const_type (DataType type, CodeContext context) {
+       static bool check_const_type (DataType type, CodeContext context) {
                if (type is ValueType) {
                        return true;
                } else if (type is ArrayType) {
                        unowned ArrayType array_type = (ArrayType) type;
                        return check_const_type (array_type.element_type, context);
-               } else if (type.type_symbol.is_subtype_of (context.analyzer.string_type.type_symbol)) {
+               } else if (type.type_symbol != null && type.type_symbol.is_subtype_of 
(context.analyzer.string_type.type_symbol)) {
                        return true;
                } else {
                        return false;
diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala
index 9ecc6c67e..5686d57d3 100644
--- a/vala/valaelementaccess.vala
+++ b/vala/valaelementaccess.vala
@@ -247,7 +247,9 @@ public class Vala.ElementAccess : Expression {
                        }
                }
 
-               value_type.check (context);
+               if (value_type != null) {
+                       value_type.check (context);
+               }
 
                return !error;
        }
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index 978ab94f8..9cddcd42e 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -345,12 +345,21 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                }
        }
 
-       Map<Variable, Set<BasicBlock>> get_assignment_map (List<BasicBlock> block_list, BasicBlock 
entry_block) {
+       Map<Variable, Set<BasicBlock>>? get_assignment_map (List<BasicBlock> block_list, BasicBlock 
entry_block) {
                var map = new HashMap<Variable, Set<BasicBlock>> ();
                foreach (BasicBlock block in block_list) {
                        var defined_variables = new ArrayList<Variable> ();
                        foreach (CodeNode node in block.get_nodes ()) {
-                               node.get_defined_variables (defined_variables);
+                               var temp_dv = new ArrayList<Variable> ();
+                               node.get_defined_variables (temp_dv);
+                               foreach (Variable v in temp_dv) {
+                                       if (v == null) {
+                                               // Should not have null variable defined when not in LSP mode.
+                                               assert (context.keep_going);
+                                               return null;
+                                       }
+                               }
+                               defined_variables.add_all (temp_dv);
                        }
 
                        foreach (Variable variable in defined_variables) {
@@ -368,6 +377,10 @@ public class Vala.FlowAnalyzer : CodeVisitor {
        void insert_phi_functions (List<BasicBlock> block_list, BasicBlock entry_block) {
                var assign = get_assignment_map (block_list, entry_block);
 
+               if (assign == null) {
+                       return;
+               }
+
                int counter = 0;
                var work_list = new ArrayList<BasicBlock> ();
 
@@ -476,6 +489,10 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        node.get_defined_variables (defined_variables);
 
                        foreach (Variable variable in defined_variables) {
+                               if (variable == null) {
+                                       assert (context.keep_going);
+                                       continue;
+                               }
                                process_assignment (var_map, variable);
                        }
                }
@@ -510,6 +527,11 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        node.get_defined_variables (defined_variables);
 
                        foreach (Variable variable in defined_variables) {
+                               if (variable == null) {
+                                       // We should not have null variables outside of LSP context.
+                                       assert (context.keep_going);
+                                       continue;
+                               }
                                var variable_stack = var_map.get (variable);
                                variable_stack.remove_at (variable_stack.size - 1);
                        }
@@ -526,11 +548,12 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        var_symbol.single_assignment = false;
                }
                Variable versioned_var;
+               DataType? var_type = var_symbol.variable_type != null ? var_symbol.variable_type.copy () : 
null;
                if (var_symbol is LocalVariable) {
-                       versioned_var = new LocalVariable (var_symbol.variable_type.copy (), var_symbol.name, 
null, var_symbol.source_reference);
+                       versioned_var = new LocalVariable (var_type, var_symbol.name, null, 
var_symbol.source_reference);
                } else {
                        // parameter
-                       versioned_var = new Parameter (var_symbol.name, var_symbol.variable_type.copy (), 
var_symbol.source_reference);
+                       versioned_var = new Parameter (var_symbol.name, var_type, 
var_symbol.source_reference);
                }
                variable_stack.add (versioned_var);
                return versioned_var;
@@ -987,7 +1010,7 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        var error_block = new BasicBlock ();
                        all_basic_blocks.add (error_block);
 
-                       if (catch_clause.error_type != null) {
+                       if (catch_clause.error_type != null && !(catch_clause.error_type is InvalidType)) {
                                if (context.profile == Profile.GOBJECT) {
                                        unowned ErrorType error_type = (ErrorType) catch_clause.error_type;
                                        jump_stack.add (new JumpTarget.error_target (error_block, 
catch_clause, catch_clause.error_type.type_symbol as ErrorDomain, error_type.error_code, null));
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 17b41b1e5..a8257fb3b 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -1381,6 +1381,12 @@ public class Vala.GirParser : CodeVisitor {
                                continue;
                        }
 
+                       if (ns == null) {
+                               // We should not have a null namespace unless we're in LSP mode.
+                               assert (context.keep_going);
+                               continue;
+                       }
+
                        provided_namespaces.add ("%s-%s".printf (gir_namespace, gir_version));
 
                        var gir_symbol = new UnresolvedSymbol (null, gir_namespace);
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 4fb7f4564..98c76f6b2 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -44,7 +44,7 @@ public class Vala.LambdaExpression : Expression {
        /**
         * The generated method.
         */
-       public Method method { get; set; }
+       public Method? method { get; set; }
 
        private List<Parameter> parameters = new ArrayList<Parameter> ();
 
@@ -249,7 +249,7 @@ public class Vala.LambdaExpression : Expression {
 
        public override void get_used_variables (Collection<Variable> collection) {
                // require captured variables to be initialized
-               if (method.closure) {
+               if (method != null && method.closure) {
                        method.get_captured_variables ((Collection<LocalVariable>) collection);
                }
        }
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 946bd2b0a..3866f6051 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -307,6 +307,9 @@ public class Vala.MemberAccess : Expression {
 
                        if (symbol_reference == null && source_reference != null) {
                                foreach (UsingDirective ns in source_reference.using_directives) {
+                                       if (!(ns.namespace_symbol is Vala.Namespace)) {
+                                               continue;
+                                       }
                                        var local_sym = ns.namespace_symbol.scope.lookup (member_name);
                                        if (local_sym != null) {
                                                if (symbol_reference != null && symbol_reference != 
local_sym) {
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index f8b1578b2..0673e0001 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -166,7 +166,9 @@ public class Vala.MethodCall : Expression {
                        // constructor
                        unowned Class cl = (Class) ((ObjectType) mtype).type_symbol;
                        unowned Method m = cl.default_construction_method;
-                       m.get_error_types (collection, source_reference);
+                       if (m != null) {
+                               m.get_error_types (collection, source_reference);
+                       }
                } else if (mtype is DelegateType) {
                        unowned Delegate d = ((DelegateType) mtype).delegate_symbol;
                        d.get_error_types (collection, source_reference);
@@ -485,7 +487,8 @@ public class Vala.MethodCall : Expression {
                foreach (Expression arg in argument_list) {
                        arg.check (context);
 
-                       if (arg is LambdaExpression && ((LambdaExpression) arg).method.closure) {
+                       if (arg is LambdaExpression && ((LambdaExpression) arg).method != null &&
+                                       ((LambdaExpression) arg).method.closure) {
                                force_lambda_method_closure = true;
                        }
                }
diff --git a/vala/valaparameter.vala b/vala/valaparameter.vala
index 978fec737..7d64c17f6 100644
--- a/vala/valaparameter.vala
+++ b/vala/valaparameter.vala
@@ -176,8 +176,8 @@ public class Vala.Parameter : Variable {
                                Report.warning (source_reference, "`null' incompatible with parameter type 
`%s'".printf (variable_type.to_string ()));
                        } else if (!(initializer is NullLiteral) && direction == ParameterDirection.OUT) {
                                Report.error (source_reference, "only `null' is allowed as default value for 
out parameters");
-                       } else if (direction == ParameterDirection.IN && !initializer.value_type.compatible 
(variable_type)) {
-                               Report.error (initializer.source_reference, "Cannot convert from `%s' to 
`%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
+                       } else if (direction == ParameterDirection.IN && (initializer.value_type == null || 
!initializer.value_type.compatible (variable_type))) {
+                               Report.error (initializer.source_reference, "Cannot convert from `%s' to 
`%s'".printf (initializer.value_type == null ? "(nil)" : initializer.value_type.to_string (), 
variable_type.to_string ()));
                        } else if (direction == ParameterDirection.REF) {
                                Report.error (source_reference, "default value not allowed for ref 
parameter");
                        } else if (!initializer.is_accessible (this)) {
diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala
index 9349b1818..d54d57eab 100644
--- a/vala/valathrowstatement.vala
+++ b/vala/valathrowstatement.vala
@@ -76,9 +76,11 @@ public class Vala.ThrowStatement : CodeNode, Statement {
                if (source_reference == null) {
                        source_reference = this.source_reference;
                }
-               var error_type = error_expression.value_type.copy ();
-               error_type.source_reference = source_reference;
-               collection.add (error_type);
+               if (error_expression.value_type != null) {
+                       var error_type = error_expression.value_type.copy ();
+                       error_type.source_reference = source_reference;
+                       collection.add (error_type);
+               }
        }
 
        public override bool check (CodeContext context) {


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