| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:collection'; | 5 import 'dart:collection'; |
| 6 import 'package:analyzer/dart/ast/ast.dart'; | 6 import 'package:analyzer/dart/ast/ast.dart'; |
| 7 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 7 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
| 8 import 'package:analyzer/dart/ast/token.dart' show TokenType; | 8 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
| 9 import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor; | 9 import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor; |
| 10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
| 11 import 'package:analyzer/dart/element/type.dart'; | 11 import 'package:analyzer/dart/element/type.dart'; |
| 12 import 'element_helpers.dart' show getStaticType, isInlineJS; | 12 import 'element_helpers.dart' show getStaticType, isInlineJS; |
| 13 import 'property_model.dart'; |
| 13 | 14 |
| 14 /// An inference engine for nullable types. | 15 /// An inference engine for nullable types. |
| 15 /// | 16 /// |
| 16 /// This can answer questions about whether expressions are nullable | 17 /// This can answer questions about whether expressions are nullable |
| 17 /// (see [isNullable]). Given a set of compilation units in a library, it will | 18 /// (see [isNullable]). Given a set of compilation units in a library, it will |
| 18 /// determine if locals can be null using flow-insensitive analysis. | 19 /// determine if locals can be null using flow-insensitive analysis. |
| 19 /// | 20 /// |
| 20 /// The analysis for null expressions is conservative and incomplete, but it can | 21 /// The analysis for null expressions is conservative and incomplete, but it can |
| 21 /// optimize some patterns. | 22 /// optimize some patterns. |
| 22 // TODO(vsm): Revisit whether we really need this when we get | 23 // TODO(vsm): Revisit whether we really need this when we get |
| 23 // better non-nullability in the type system. | 24 // better non-nullability in the type system. |
| 24 abstract class NullableTypeInference { | 25 abstract class NullableTypeInference { |
| 25 LibraryElement get dartCoreLibrary; | 26 LibraryElement get dartCoreLibrary; |
| 27 VirtualFieldModel get virtualFields; |
| 28 |
| 26 bool isPrimitiveType(DartType type); | 29 bool isPrimitiveType(DartType type); |
| 27 bool isObjectMember(String name); | 30 bool isObjectMember(String name); |
| 28 | 31 |
| 29 /// Known non-null local variables. | 32 /// Known non-null local variables. |
| 30 HashSet<LocalVariableElement> _notNullLocals; | 33 HashSet<LocalVariableElement> _notNullLocals; |
| 31 | 34 |
| 32 void inferNullableTypes(AstNode node) { | 35 void inferNullableTypes(AstNode node) { |
| 33 var visitor = new _NullableLocalInference(this); | 36 var visitor = new _NullableLocalInference(this); |
| 34 node.accept(visitor); | 37 node.accept(visitor); |
| 35 _notNullLocals = visitor.computeNotNullLocals(); | 38 _notNullLocals = visitor.computeNotNullLocals(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 return !_notNullLocals.contains(element); | 77 return !_notNullLocals.contains(element); |
| 75 } | 78 } |
| 76 | 79 |
| 77 if (element is FunctionElement || element is MethodElement) { | 80 if (element is FunctionElement || element is MethodElement) { |
| 78 // A function or method. This can't be null. | 81 // A function or method. This can't be null. |
| 79 return false; | 82 return false; |
| 80 } | 83 } |
| 81 | 84 |
| 82 if (element is PropertyAccessorElement && element.isGetter) { | 85 if (element is PropertyAccessorElement && element.isGetter) { |
| 83 PropertyInducingElement variable = element.variable; | 86 PropertyInducingElement variable = element.variable; |
| 84 var isVirtual = variable is FieldElement && variable.isVirtual; | 87 var isVirtual = |
| 88 variable is FieldElement && virtualFields.isVirtual(variable); |
| 85 return isVirtual || (variable.computeConstantValue()?.isNull ?? true); | 89 return isVirtual || (variable.computeConstantValue()?.isNull ?? true); |
| 86 } | 90 } |
| 87 | 91 |
| 88 // Other types of identifiers are nullable (parameters, fields). | 92 // Other types of identifiers are nullable (parameters, fields). |
| 89 return true; | 93 return true; |
| 90 } | 94 } |
| 91 | 95 |
| 92 if (expr is Literal) return expr is NullLiteral; | 96 if (expr is Literal) return expr is NullLiteral; |
| 93 if (expr is IsExpression) return false; | 97 if (expr is IsExpression) return false; |
| 94 if (expr is FunctionExpression) return false; | 98 if (expr is FunctionExpression) return false; |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 return false; | 325 return false; |
| 322 } | 326 } |
| 323 | 327 |
| 324 if (_nullInference._isNullable(right, visitLocal)) { | 328 if (_nullInference._isNullable(right, visitLocal)) { |
| 325 _nullableLocals.add(element); | 329 _nullableLocals.add(element); |
| 326 } | 330 } |
| 327 } | 331 } |
| 328 } | 332 } |
| 329 } | 333 } |
| 330 } | 334 } |
| OLD | NEW |