| 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 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
| 6 // refactored to fit into analyzer. | 6 // refactored to fit into analyzer. |
| 7 library analyzer.src.task.strong.checker; | 7 library analyzer.src.task.strong.checker; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; | 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
| 12 import 'package:analyzer/dart/ast/token.dart'; | 12 import 'package:analyzer/dart/ast/token.dart'; |
| 13 import 'package:analyzer/dart/ast/visitor.dart'; | 13 import 'package:analyzer/dart/ast/visitor.dart'; |
| 14 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
| 15 import 'package:analyzer/dart/element/type.dart'; | 15 import 'package:analyzer/dart/element/type.dart'; |
| 16 import 'package:analyzer/src/dart/element/type.dart'; | 16 import 'package:analyzer/src/dart/element/type.dart'; |
| 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; | 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; |
| 18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; | 18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; |
| 19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 20 import 'package:analyzer/src/generated/type_system.dart'; | 20 import 'package:analyzer/src/generated/type_system.dart'; |
| 21 | 21 |
| 22 import 'ast_properties.dart'; | 22 import 'ast_properties.dart'; |
| 23 | 23 |
| 24 bool isKnownFunction(Expression expression, {bool instanceMethods: false}) { | 24 bool isKnownFunction(Expression expression) { |
| 25 Element element = null; | 25 var element = _getKnownElement(expression); |
| 26 // First class functions and static methods, where we know the original |
| 27 // declaration, will have an exact type, so we know a downcast will fail. |
| 28 return element is FunctionElement || |
| 29 element is MethodElement && element.isStatic; |
| 30 } |
| 31 |
| 32 bool _hasStrictArrow(Expression expression) { |
| 33 var element = _getKnownElement(expression); |
| 34 return element is FunctionElement || element is MethodElement; |
| 35 } |
| 36 |
| 37 Element _getKnownElement(Expression expression) { |
| 26 if (expression is ParenthesizedExpression) { | 38 if (expression is ParenthesizedExpression) { |
| 27 expression = (expression as ParenthesizedExpression).expression; | 39 expression = (expression as ParenthesizedExpression).expression; |
| 28 } | 40 } |
| 29 if (expression is FunctionExpression) { | 41 if (expression is FunctionExpression) { |
| 30 return true; | 42 return expression.element; |
| 31 } else if (expression is PropertyAccess) { | 43 } else if (expression is PropertyAccess) { |
| 32 element = expression.propertyName.staticElement; | 44 return expression.propertyName.staticElement; |
| 33 } else if (expression is Identifier) { | 45 } else if (expression is Identifier) { |
| 34 element = expression.staticElement; | 46 return expression.staticElement; |
| 35 } | 47 } |
| 36 // First class functions and static methods, where we know the original | 48 return null; |
| 37 // declaration, will have an exact type, so we know a downcast will fail. | |
| 38 return element is FunctionElement || | |
| 39 element is MethodElement && (instanceMethods || element.isStatic); | |
| 40 } | 49 } |
| 41 | 50 |
| 42 DartType _elementType(Element e) { | 51 DartType _elementType(Element e) { |
| 43 if (e == null) { | 52 if (e == null) { |
| 44 // Malformed code - just return dynamic. | 53 // Malformed code - just return dynamic. |
| 45 return DynamicTypeImpl.instance; | 54 return DynamicTypeImpl.instance; |
| 46 } | 55 } |
| 47 return (e as dynamic).type; | 56 return (e as dynamic).type; |
| 48 } | 57 } |
| 49 | 58 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 baseMethod = type.getSetter(memberName); | 113 baseMethod = type.getSetter(memberName); |
| 105 } else { | 114 } else { |
| 106 baseMethod = type.getMethod(memberName); | 115 baseMethod = type.getMethod(memberName); |
| 107 } | 116 } |
| 108 } catch (e) { | 117 } catch (e) { |
| 109 // TODO(sigmund): remove this try-catch block (see issue #48). | 118 // TODO(sigmund): remove this try-catch block (see issue #48). |
| 110 } | 119 } |
| 111 if (baseMethod == null || baseMethod.isStatic) return null; | 120 if (baseMethod == null || baseMethod.isStatic) return null; |
| 112 return baseMethod.type; | 121 return baseMethod.type; |
| 113 } | 122 } |
| 123 |
| 114 return f; | 124 return f; |
| 115 } | 125 } |
| 116 | 126 |
| 117 typedef FunctionType _MemberTypeGetter(InterfaceType type); | 127 typedef FunctionType _MemberTypeGetter(InterfaceType type); |
| 118 | 128 |
| 119 /// Checks the body of functions and properties. | 129 /// Checks the body of functions and properties. |
| 120 class CodeChecker extends RecursiveAstVisitor { | 130 class CodeChecker extends RecursiveAstVisitor { |
| 121 final StrongTypeSystemImpl rules; | 131 final StrongTypeSystemImpl rules; |
| 122 final TypeProvider typeProvider; | 132 final TypeProvider typeProvider; |
| 123 final AnalysisErrorListener reporter; | 133 final AnalysisErrorListener reporter; |
| (...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 956 } else { | 966 } else { |
| 957 // Malformed type - fallback on analyzer error. | 967 // Malformed type - fallback on analyzer error. |
| 958 return null; | 968 return null; |
| 959 } | 969 } |
| 960 } | 970 } |
| 961 | 971 |
| 962 DartType _getStaticType(Expression expr) { | 972 DartType _getStaticType(Expression expr) { |
| 963 DartType t = expr.staticType ?? DynamicTypeImpl.instance; | 973 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| 964 | 974 |
| 965 // Remove fuzzy arrow if possible. | 975 // Remove fuzzy arrow if possible. |
| 966 if (t is FunctionType && isKnownFunction(expr)) { | 976 if (t is FunctionType && _hasStrictArrow(expr)) { |
| 967 t = rules.functionTypeToConcreteType(typeProvider, t); | 977 t = rules.functionTypeToConcreteType(typeProvider, t); |
| 968 } | 978 } |
| 969 | 979 |
| 970 return t; | 980 return t; |
| 971 } | 981 } |
| 972 | 982 |
| 973 /// Given an expression, return its type assuming it is | 983 /// Given an expression, return its type assuming it is |
| 974 /// in the caller position of a call (that is, accounting | 984 /// in the caller position of a call (that is, accounting |
| 975 /// for the possibility of a call method). Returns null | 985 /// for the possibility of a call method). Returns null |
| 976 /// if expression is not statically callable. | 986 /// if expression is not statically callable. |
| 977 FunctionType _getTypeAsCaller(Expression node) { | 987 FunctionType _getTypeAsCaller(Expression node) { |
| 978 DartType t = node.staticType; | 988 DartType t = _getStaticType(node); |
| 979 if (node is SimpleIdentifier) { | 989 if (node is SimpleIdentifier) { |
| 980 Expression parent = node.parent; | 990 Expression parent = node.parent; |
| 981 if (parent is MethodInvocation) { | 991 if (parent is MethodInvocation) { |
| 982 t = parent.staticInvokeType; | 992 t = parent.staticInvokeType; |
| 983 } | 993 } |
| 984 } | 994 } |
| 985 if (t is InterfaceType) { | 995 if (t is InterfaceType) { |
| 986 return rules.getCallMethodType(t); | 996 return rules.getCallMethodType(t); |
| 987 } | 997 } |
| 988 if (t is FunctionType) { | 998 if (t is FunctionType) { |
| 989 return t; | 999 return t; |
| 990 } | 1000 } |
| 991 return null; | 1001 return null; |
| 992 } | 1002 } |
| 993 | 1003 |
| 994 /// Returns `true` if the expression is a dynamic function call or method | 1004 /// Returns `true` if the expression is a dynamic function call or method |
| 995 /// invocation. | 1005 /// invocation. |
| 996 bool _isDynamicCall(Expression call) { | 1006 bool _isDynamicCall(Expression call) { |
| 997 var ft = _getTypeAsCaller(call); | 1007 var ft = _getTypeAsCaller(call); |
| 998 // TODO(leafp): This will currently return true if t is Function | 1008 // TODO(leafp): This will currently return true if t is Function |
| 999 // This is probably the most correct thing to do for now, since | 1009 // This is probably the most correct thing to do for now, since |
| 1000 // this code is also used by the back end. Maybe revisit at some | 1010 // this code is also used by the back end. Maybe revisit at some |
| 1001 // point? | 1011 // point? |
| 1002 if (ft == null) return true; | 1012 if (ft == null) return true; |
| 1003 // Dynamic as the parameter type is treated as bottom. A function with | 1013 // Dynamic as the parameter type is treated as bottom. A function with |
| 1004 // a dynamic parameter type requires a dynamic call in general. | 1014 // a dynamic parameter type requires a dynamic call in general. |
| 1005 // However, as an optimization, if we have an original definition, we know | 1015 // However, as an optimization, if we have an original definition, we know |
| 1006 // dynamic is reified as Object - in this case a regular call is fine. | 1016 // dynamic is reified as Object - in this case a regular call is fine. |
| 1007 if (isKnownFunction(call, instanceMethods: true)) { | 1017 if (_hasStrictArrow(call)) { |
| 1008 return false; | 1018 return false; |
| 1009 } | 1019 } |
| 1010 return rules.anyParameterType(ft, (pt) => pt.isDynamic); | 1020 return rules.anyParameterType(ft, (pt) => pt.isDynamic); |
| 1011 } | 1021 } |
| 1012 | 1022 |
| 1013 /// Returns `true` if the target expression is dynamic. | 1023 /// Returns `true` if the target expression is dynamic. |
| 1014 bool _isDynamicTarget(Expression node) { | 1024 bool _isDynamicTarget(Expression node) { |
| 1015 if (node == null) return false; | 1025 if (node == null) return false; |
| 1016 | 1026 |
| 1017 if (_isLibraryPrefix(node)) return false; | 1027 if (_isLibraryPrefix(node)) return false; |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 AstNode errorLocation, | 1291 AstNode errorLocation, |
| 1282 Set<String> seen, | 1292 Set<String> seen, |
| 1283 bool isSubclass) { | 1293 bool isSubclass) { |
| 1284 void checkHelper(ExecutableElement e) { | 1294 void checkHelper(ExecutableElement e) { |
| 1285 if (e.isStatic) return; | 1295 if (e.isStatic) return; |
| 1286 if (seen.contains(e.name)) return; | 1296 if (seen.contains(e.name)) return; |
| 1287 if (_checkSingleOverride(e, baseType, null, errorLocation, isSubclass)) { | 1297 if (_checkSingleOverride(e, baseType, null, errorLocation, isSubclass)) { |
| 1288 seen.add(e.name); | 1298 seen.add(e.name); |
| 1289 } | 1299 } |
| 1290 } | 1300 } |
| 1301 |
| 1291 subType.methods.forEach(checkHelper); | 1302 subType.methods.forEach(checkHelper); |
| 1292 subType.accessors.forEach(checkHelper); | 1303 subType.accessors.forEach(checkHelper); |
| 1293 } | 1304 } |
| 1294 | 1305 |
| 1295 /// Checks that [cls] and its super classes (including mixins) correctly | 1306 /// Checks that [cls] and its super classes (including mixins) correctly |
| 1296 /// overrides each interface in [interfaces]. If [includeParents] is false, | 1307 /// overrides each interface in [interfaces]. If [includeParents] is false, |
| 1297 /// then mixins are still checked, but the base type and it's transitive | 1308 /// then mixins are still checked, but the base type and it's transitive |
| 1298 /// supertypes are not. | 1309 /// supertypes are not. |
| 1299 /// | 1310 /// |
| 1300 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For | 1311 /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1503 var visited = new Set<InterfaceType>(); | 1514 var visited = new Set<InterfaceType>(); |
| 1504 do { | 1515 do { |
| 1505 visited.add(current); | 1516 visited.add(current); |
| 1506 current.mixins.reversed.forEach( | 1517 current.mixins.reversed.forEach( |
| 1507 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1518 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1508 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1519 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1509 current = current.superclass; | 1520 current = current.superclass; |
| 1510 } while (!current.isObject && !visited.contains(current)); | 1521 } while (!current.isObject && !visited.contains(current)); |
| 1511 } | 1522 } |
| 1512 } | 1523 } |
| OLD | NEW |