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 |