Chromium Code Reviews| 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/visitor.dart'; | 13 import 'package:analyzer/dart/ast/visitor.dart'; |
| 13 import 'package:analyzer/dart/element/element.dart'; | 14 import 'package:analyzer/dart/element/element.dart'; |
| 14 import 'package:analyzer/dart/element/type.dart'; | 15 import 'package:analyzer/dart/element/type.dart'; |
| 15 import 'package:analyzer/src/dart/element/type.dart'; | 16 import 'package:analyzer/src/dart/element/type.dart'; |
| 16 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; | 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; |
| 17 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; | 18 import 'package:analyzer/src/generated/error.dart' show StrongModeCode; |
| 18 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 19 import 'package:analyzer/src/generated/type_system.dart'; | 20 import 'package:analyzer/src/generated/type_system.dart'; |
| 20 | 21 |
| 21 import 'ast_properties.dart'; | 22 import 'ast_properties.dart'; |
| 22 | 23 |
| 24 bool isKnownFunction(Expression expression) { | |
| 25 Element element = null; | |
| 26 if (expression is FunctionExpression) { | |
| 27 return true; | |
| 28 } else if (expression is PropertyAccess) { | |
| 29 element = expression.propertyName.staticElement; | |
| 30 } else if (expression is Identifier) { | |
| 31 element = expression.staticElement; | |
| 32 } | |
| 33 // First class functions and static methods, where we know the original | |
| 34 // declaration, will have an exact type, so we know a downcast will fail. | |
| 35 return element is FunctionElement || | |
| 36 element is MethodElement && element.isStatic; | |
| 37 } | |
| 38 | |
| 23 DartType _elementType(Element e) { | 39 DartType _elementType(Element e) { |
| 24 if (e == null) { | 40 if (e == null) { |
| 25 // Malformed code - just return dynamic. | 41 // Malformed code - just return dynamic. |
| 26 return DynamicTypeImpl.instance; | 42 return DynamicTypeImpl.instance; |
| 27 } | 43 } |
| 28 return (e as dynamic).type; | 44 return (e as dynamic).type; |
| 29 } | 45 } |
| 30 | 46 |
| 47 // Return the field on type corresponding to member, or null if none | |
| 48 // exists or the "field" is actually a getter/setter. | |
|
scheglov
2016/08/02 15:25:03
Make this a documentation comment?
Brian Wilkerson
2016/08/02 15:33:53
Or delete it. I didn't add this comment, it was mo
| |
| 31 PropertyInducingElement _getMemberField( | 49 PropertyInducingElement _getMemberField( |
| 32 InterfaceType type, PropertyAccessorElement member) { | 50 InterfaceType type, PropertyAccessorElement member) { |
| 33 String memberName = member.name; | 51 String memberName = member.name; |
| 34 PropertyInducingElement field; | 52 PropertyInducingElement field; |
| 35 if (member.isGetter) { | 53 if (member.isGetter) { |
| 36 // The subclass member is an explicit getter or a field | 54 // The subclass member is an explicit getter or a field |
| 37 // - lookup the getter on the superclass. | 55 // - lookup the getter on the superclass. |
| 38 var getter = type.getGetter(memberName); | 56 var getter = type.getGetter(memberName); |
| 39 if (getter == null || getter.isStatic) return null; | 57 if (getter == null || getter.isStatic) return null; |
| 40 field = getter.variable; | 58 field = getter.variable; |
| 41 } else if (!member.isSynthetic) { | 59 } else if (!member.isSynthetic) { |
| 42 // The subclass member is an explicit setter | 60 // The subclass member is an explicit setter |
| 43 // - lookup the setter on the superclass. | 61 // - lookup the setter on the superclass. |
| 44 // Note: an implicit (synthetic) setter would have already been flagged on | 62 // Note: an implicit (synthetic) setter would have already been flagged on |
| 45 // the getter above. | 63 // the getter above. |
| 46 var setter = type.getSetter(memberName); | 64 var setter = type.getSetter(memberName); |
| 47 if (setter == null || setter.isStatic) return null; | 65 if (setter == null || setter.isStatic) return null; |
| 48 field = setter.variable; | 66 field = setter.variable; |
| 49 } else { | 67 } else { |
| 50 return null; | 68 return null; |
| 51 } | 69 } |
| 52 if (field.isSynthetic) return null; | 70 if (field.isSynthetic) return null; |
| 53 return field; | 71 return field; |
| 54 } | 72 } |
| 55 | 73 |
| 56 // Return the field on type corresponding to member, or null if none | |
| 57 // exists or the "field" is actually a getter/setter. | |
| 58 /// Looks up the declaration that matches [member] in [type] and returns it's | 74 /// Looks up the declaration that matches [member] in [type] and returns it's |
| 59 /// declared type. | 75 /// declared type. |
| 60 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) => | 76 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) => |
| 61 _memberTypeGetter(member)(type); | 77 _memberTypeGetter(member)(type); |
| 62 | 78 |
| 63 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) { | 79 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) { |
| 64 String memberName = member.name; | 80 String memberName = member.name; |
| 65 final isGetter = member is PropertyAccessorElement && member.isGetter; | 81 final isGetter = member is PropertyAccessorElement && member.isGetter; |
| 66 final isSetter = member is PropertyAccessorElement && member.isSetter; | 82 final isSetter = member is PropertyAccessorElement && member.isSetter; |
| 67 | 83 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 | 185 |
| 170 DartType getType(TypeName name) { | 186 DartType getType(TypeName name) { |
| 171 return (name == null) ? DynamicTypeImpl.instance : name.type; | 187 return (name == null) ? DynamicTypeImpl.instance : name.type; |
| 172 } | 188 } |
| 173 | 189 |
| 174 void reset() { | 190 void reset() { |
| 175 _failure = false; | 191 _failure = false; |
| 176 } | 192 } |
| 177 | 193 |
| 178 @override | 194 @override |
| 179 void visitCompilationUnit(CompilationUnit node) { | |
| 180 _hasImplicitCasts = false; | |
| 181 node.visitChildren(this); | |
| 182 setHasImplicitCasts(node, _hasImplicitCasts); | |
| 183 } | |
| 184 | |
| 185 @override | |
| 186 void visitAsExpression(AsExpression node) { | 195 void visitAsExpression(AsExpression node) { |
| 187 // We could do the same check as the IsExpression below, but that is | 196 // We could do the same check as the IsExpression below, but that is |
| 188 // potentially too conservative. Instead, at runtime, we must fail hard | 197 // potentially too conservative. Instead, at runtime, we must fail hard |
| 189 // if the Dart as and the DDC as would return different values. | 198 // if the Dart as and the DDC as would return different values. |
| 190 node.visitChildren(this); | 199 node.visitChildren(this); |
| 191 } | 200 } |
| 192 | 201 |
| 193 @override | 202 @override |
| 194 void visitAssignmentExpression(AssignmentExpression node) { | 203 void visitAssignmentExpression(AssignmentExpression node) { |
| 195 var token = node.operator; | 204 Token operator = node.operator; |
| 196 if (token.type == TokenType.EQ || | 205 TokenType operatorType = operator.type; |
| 197 token.type == TokenType.QUESTION_QUESTION_EQ) { | 206 if (operatorType == TokenType.EQ || |
| 207 operatorType == TokenType.QUESTION_QUESTION_EQ) { | |
| 198 DartType staticType = _getStaticType(node.leftHandSide); | 208 DartType staticType = _getStaticType(node.leftHandSide); |
| 199 checkAssignment(node.rightHandSide, staticType); | 209 checkAssignment(node.rightHandSide, staticType); |
| 210 } else if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ || | |
| 211 operatorType == TokenType.BAR_BAR_EQ) { | |
| 212 checkAssignment(node.leftHandSide, typeProvider.boolType); | |
| 213 checkAssignment(node.rightHandSide, typeProvider.boolType); | |
| 200 } else { | 214 } else { |
| 201 _checkCompoundAssignment(node); | 215 _checkCompoundAssignment(node); |
| 202 } | 216 } |
| 203 node.visitChildren(this); | 217 node.visitChildren(this); |
| 204 } | 218 } |
| 205 | 219 |
| 206 @override | 220 @override |
| 207 void visitBinaryExpression(BinaryExpression node) { | 221 void visitBinaryExpression(BinaryExpression node) { |
| 208 var op = node.operator; | 222 var op = node.operator; |
| 209 if (op.isUserDefinableOperator) { | 223 if (op.isUserDefinableOperator) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 super.visitClassDeclaration(node); | 266 super.visitClassDeclaration(node); |
| 253 } | 267 } |
| 254 | 268 |
| 255 @override | 269 @override |
| 256 void visitComment(Comment node) { | 270 void visitComment(Comment node) { |
| 257 // skip, no need to do typechecking inside comments (they may contain | 271 // skip, no need to do typechecking inside comments (they may contain |
| 258 // comment references which would require resolution). | 272 // comment references which would require resolution). |
| 259 } | 273 } |
| 260 | 274 |
| 261 @override | 275 @override |
| 276 void visitCompilationUnit(CompilationUnit node) { | |
| 277 _hasImplicitCasts = false; | |
| 278 node.visitChildren(this); | |
| 279 setHasImplicitCasts(node, _hasImplicitCasts); | |
| 280 } | |
| 281 | |
| 282 @override | |
| 262 void visitConditionalExpression(ConditionalExpression node) { | 283 void visitConditionalExpression(ConditionalExpression node) { |
| 263 checkBoolean(node.condition); | 284 checkBoolean(node.condition); |
| 264 node.visitChildren(this); | 285 node.visitChildren(this); |
| 265 } | 286 } |
| 266 | 287 |
| 267 /// Check constructor declaration to ensure correct super call placement. | 288 /// Check constructor declaration to ensure correct super call placement. |
| 268 @override | 289 @override |
| 269 void visitConstructorDeclaration(ConstructorDeclaration node) { | 290 void visitConstructorDeclaration(ConstructorDeclaration node) { |
| 270 node.visitChildren(this); | 291 node.visitChildren(this); |
| 271 | 292 |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 op.type == TokenType.MINUS_MINUS) { | 867 op.type == TokenType.MINUS_MINUS) { |
| 847 if (_isDynamicTarget(node.operand)) { | 868 if (_isDynamicTarget(node.operand)) { |
| 848 _recordDynamicInvoke(node, node.operand); | 869 _recordDynamicInvoke(node, node.operand); |
| 849 } | 870 } |
| 850 // For ++ and --, even if it is not dynamic, we still need to check | 871 // For ++ and --, even if it is not dynamic, we still need to check |
| 851 // that the user defined method accepts an `int` as the RHS. | 872 // that the user defined method accepts an `int` as the RHS. |
| 852 // We assume Analyzer has done this already. | 873 // We assume Analyzer has done this already. |
| 853 } | 874 } |
| 854 } | 875 } |
| 855 | 876 |
| 856 /// Records an implicit cast for the [expression] from [fromType] to [toType]. | |
| 857 /// | |
| 858 /// This will emit the appropriate error/warning/hint message as well as mark | |
| 859 /// the AST node. | |
| 860 void _recordImplicitCast( | |
| 861 Expression expression, DartType fromType, DartType toType) { | |
| 862 // toT <:_R fromT => to <: fromT | |
| 863 // NB: classes with call methods are subtypes of function | |
| 864 // types, but the function type is not assignable to the class | |
| 865 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); | |
| 866 | |
| 867 // Inference "casts": | |
| 868 if (expression is Literal || expression is FunctionExpression) { | |
| 869 // fromT should be an exact type - this will almost certainly fail at | |
| 870 // runtime. | |
| 871 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 872 [expression, fromType, toType]); | |
| 873 return; | |
| 874 } | |
| 875 | |
| 876 if (expression is InstanceCreationExpression) { | |
| 877 ConstructorElement e = expression.staticElement; | |
| 878 if (e == null || !e.isFactory) { | |
| 879 // fromT should be an exact type - this will almost certainly fail at | |
| 880 // runtime. | |
| 881 | |
| 882 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 883 [expression, fromType, toType]); | |
| 884 return; | |
| 885 } | |
| 886 } | |
| 887 | |
| 888 if (isKnownFunction(expression)) { | |
| 889 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 890 [expression, fromType, toType]); | |
| 891 return; | |
| 892 } | |
| 893 | |
| 894 // TODO(vsm): Change this to an assert when we have generic methods and | |
| 895 // fix TypeRules._coerceTo to disallow implicit sideways casts. | |
| 896 bool downCastComposite = false; | |
| 897 if (!rules.isSubtypeOf(toType, fromType)) { | |
| 898 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); | |
| 899 downCastComposite = true; | |
| 900 } | |
| 901 | |
| 902 // Composite cast: these are more likely to fail. | |
| 903 if (!rules.isGroundType(toType)) { | |
| 904 // This cast is (probably) due to our different treatment of dynamic. | |
| 905 // It may be more likely to fail at runtime. | |
| 906 if (fromType is InterfaceType) { | |
| 907 // For class types, we'd like to allow non-generic down casts, e.g., | |
| 908 // Iterable<T> to List<T>. The intuition here is that raw (generic) | |
| 909 // casts are problematic, and we should complain about those. | |
| 910 var typeArgs = fromType.typeArguments; | |
| 911 downCastComposite = | |
| 912 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic); | |
| 913 } else { | |
| 914 downCastComposite = true; | |
| 915 } | |
| 916 } | |
| 917 | |
| 918 var parent = expression.parent; | |
| 919 ErrorCode errorCode; | |
| 920 if (downCastComposite) { | |
| 921 errorCode = StrongModeCode.DOWN_CAST_COMPOSITE; | |
| 922 } else if (fromType.isDynamic) { | |
| 923 errorCode = StrongModeCode.DYNAMIC_CAST; | |
| 924 } else if (parent is VariableDeclaration && | |
| 925 parent.initializer == expression) { | |
| 926 errorCode = StrongModeCode.ASSIGNMENT_CAST; | |
| 927 } else { | |
| 928 errorCode = StrongModeCode.DOWN_CAST_IMPLICIT; | |
| 929 } | |
| 930 | |
| 931 _recordMessage(expression, errorCode, [fromType, toType]); | |
| 932 setImplicitCast(expression, toType); | |
| 933 _hasImplicitCasts = true; | |
| 934 } | |
| 935 | |
| 936 // Produce a coercion which coerces something of type fromT | |
| 937 // to something of type toT. | |
| 938 // Returns the error coercion if the types cannot be coerced | |
| 939 // according to our current criteria. | |
| 940 /// Gets the expected return type of the given function [body], either from | 877 /// Gets the expected return type of the given function [body], either from |
| 941 /// a normal return/yield, or from a yield*. | 878 /// a normal return/yield, or from a yield*. |
| 942 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { | 879 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { |
| 943 FunctionType functionType; | 880 FunctionType functionType; |
| 944 var parent = body.parent; | 881 var parent = body.parent; |
| 945 if (parent is Declaration) { | 882 if (parent is Declaration) { |
| 946 functionType = _elementType(parent.element); | 883 functionType = _elementType(parent.element); |
| 947 } else { | 884 } else { |
| 948 assert(parent is FunctionExpression); | 885 assert(parent is FunctionExpression); |
| 949 functionType = | 886 functionType = |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 984 if (type.isDynamic) { | 921 if (type.isDynamic) { |
| 985 return type; | 922 return type; |
| 986 } else if (type is InterfaceType && type.element == expectedType.element) { | 923 } else if (type is InterfaceType && type.element == expectedType.element) { |
| 987 return type.typeArguments[0]; | 924 return type.typeArguments[0]; |
| 988 } else { | 925 } else { |
| 989 // Malformed type - fallback on analyzer error. | 926 // Malformed type - fallback on analyzer error. |
| 990 return null; | 927 return null; |
| 991 } | 928 } |
| 992 } | 929 } |
| 993 | 930 |
| 931 // Produce a coercion which coerces something of type fromT | |
| 932 // to something of type toT. | |
| 933 // Returns the error coercion if the types cannot be coerced | |
| 934 // according to our current criteria. | |
|
scheglov
2016/08/02 15:25:03
Make this a documentation comment?
Brian Wilkerson
2016/08/02 15:33:53
I didn't write this comment either, it was also mo
| |
| 994 DartType _getStaticType(Expression expr) { | 935 DartType _getStaticType(Expression expr) { |
| 995 DartType t = expr.staticType ?? DynamicTypeImpl.instance; | 936 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| 996 | 937 |
| 997 // Remove fuzzy arrow if possible. | 938 // Remove fuzzy arrow if possible. |
| 998 if (t is FunctionType && isKnownFunction(expr)) { | 939 if (t is FunctionType && isKnownFunction(expr)) { |
| 999 t = rules.functionTypeToConcreteType(typeProvider, t); | 940 t = rules.functionTypeToConcreteType(typeProvider, t); |
| 1000 } | 941 } |
| 1001 | 942 |
| 1002 return t; | 943 return t; |
| 1003 } | 944 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1078 } | 1019 } |
| 1079 | 1020 |
| 1080 void _recordDynamicInvoke(AstNode node, Expression target) { | 1021 void _recordDynamicInvoke(AstNode node, Expression target) { |
| 1081 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]); | 1022 _recordMessage(node, StrongModeCode.DYNAMIC_INVOKE, [node]); |
| 1082 // TODO(jmesserly): we may eventually want to record if the whole operation | 1023 // TODO(jmesserly): we may eventually want to record if the whole operation |
| 1083 // (node) was dynamic, rather than the target, but this is an easier fit | 1024 // (node) was dynamic, rather than the target, but this is an easier fit |
| 1084 // with what we used to do. | 1025 // with what we used to do. |
| 1085 setIsDynamicInvoke(target, true); | 1026 setIsDynamicInvoke(target, true); |
| 1086 } | 1027 } |
| 1087 | 1028 |
| 1029 /// Records an implicit cast for the [expression] from [fromType] to [toType]. | |
| 1030 /// | |
| 1031 /// This will emit the appropriate error/warning/hint message as well as mark | |
| 1032 /// the AST node. | |
| 1033 void _recordImplicitCast( | |
| 1034 Expression expression, DartType fromType, DartType toType) { | |
| 1035 // toT <:_R fromT => to <: fromT | |
| 1036 // NB: classes with call methods are subtypes of function | |
| 1037 // types, but the function type is not assignable to the class | |
| 1038 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); | |
| 1039 | |
| 1040 // Inference "casts": | |
| 1041 if (expression is Literal || expression is FunctionExpression) { | |
| 1042 // fromT should be an exact type - this will almost certainly fail at | |
| 1043 // runtime. | |
| 1044 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 1045 [expression, fromType, toType]); | |
| 1046 return; | |
| 1047 } | |
| 1048 | |
| 1049 if (expression is InstanceCreationExpression) { | |
| 1050 ConstructorElement e = expression.staticElement; | |
| 1051 if (e == null || !e.isFactory) { | |
| 1052 // fromT should be an exact type - this will almost certainly fail at | |
| 1053 // runtime. | |
| 1054 | |
| 1055 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 1056 [expression, fromType, toType]); | |
| 1057 return; | |
| 1058 } | |
| 1059 } | |
| 1060 | |
| 1061 if (isKnownFunction(expression)) { | |
| 1062 _recordMessage(expression, StrongModeCode.STATIC_TYPE_ERROR, | |
| 1063 [expression, fromType, toType]); | |
| 1064 return; | |
| 1065 } | |
| 1066 | |
| 1067 // TODO(vsm): Change this to an assert when we have generic methods and | |
| 1068 // fix TypeRules._coerceTo to disallow implicit sideways casts. | |
| 1069 bool downCastComposite = false; | |
| 1070 if (!rules.isSubtypeOf(toType, fromType)) { | |
| 1071 assert(toType.isSubtypeOf(fromType) || fromType.isAssignableTo(toType)); | |
| 1072 downCastComposite = true; | |
| 1073 } | |
| 1074 | |
| 1075 // Composite cast: these are more likely to fail. | |
| 1076 if (!rules.isGroundType(toType)) { | |
| 1077 // This cast is (probably) due to our different treatment of dynamic. | |
| 1078 // It may be more likely to fail at runtime. | |
| 1079 if (fromType is InterfaceType) { | |
| 1080 // For class types, we'd like to allow non-generic down casts, e.g., | |
| 1081 // Iterable<T> to List<T>. The intuition here is that raw (generic) | |
| 1082 // casts are problematic, and we should complain about those. | |
| 1083 var typeArgs = fromType.typeArguments; | |
| 1084 downCastComposite = | |
| 1085 typeArgs.isEmpty || typeArgs.any((t) => t.isDynamic); | |
| 1086 } else { | |
| 1087 downCastComposite = true; | |
| 1088 } | |
| 1089 } | |
| 1090 | |
| 1091 var parent = expression.parent; | |
| 1092 ErrorCode errorCode; | |
| 1093 if (downCastComposite) { | |
| 1094 errorCode = StrongModeCode.DOWN_CAST_COMPOSITE; | |
| 1095 } else if (fromType.isDynamic) { | |
| 1096 errorCode = StrongModeCode.DYNAMIC_CAST; | |
| 1097 } else if (parent is VariableDeclaration && | |
| 1098 parent.initializer == expression) { | |
| 1099 errorCode = StrongModeCode.ASSIGNMENT_CAST; | |
| 1100 } else { | |
| 1101 errorCode = StrongModeCode.DOWN_CAST_IMPLICIT; | |
| 1102 } | |
| 1103 | |
| 1104 _recordMessage(expression, errorCode, [fromType, toType]); | |
| 1105 setImplicitCast(expression, toType); | |
| 1106 _hasImplicitCasts = true; | |
| 1107 } | |
| 1108 | |
| 1088 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) { | 1109 void _recordMessage(AstNode node, ErrorCode errorCode, List arguments) { |
| 1089 var severity = errorCode.errorSeverity; | 1110 var severity = errorCode.errorSeverity; |
| 1090 if (severity == ErrorSeverity.ERROR) _failure = true; | 1111 if (severity == ErrorSeverity.ERROR) _failure = true; |
| 1091 if (severity != ErrorSeverity.INFO || _options.strongModeHints) { | 1112 if (severity != ErrorSeverity.INFO || _options.strongModeHints) { |
| 1092 int begin = node is AnnotatedNode | 1113 int begin = node is AnnotatedNode |
| 1093 ? node.firstTokenAfterCommentAndMetadata.offset | 1114 ? node.firstTokenAfterCommentAndMetadata.offset |
| 1094 : node.offset; | 1115 : node.offset; |
| 1095 int length = node.end - begin; | 1116 int length = node.end - begin; |
| 1096 var source = (node.root as CompilationUnit).element.source; | 1117 var source = (node.root as CompilationUnit).element.source; |
| 1097 var error = | 1118 var error = |
| 1098 new AnalysisError(source, begin, length, errorCode, arguments); | 1119 new AnalysisError(source, begin, length, errorCode, arguments); |
| 1099 reporter.onError(error); | 1120 reporter.onError(error); |
| 1100 } | 1121 } |
| 1101 } | 1122 } |
| 1102 } | 1123 } |
| 1103 | 1124 |
| 1104 bool isKnownFunction(Expression expression) { | |
| 1105 Element element = null; | |
| 1106 if (expression is FunctionExpression) { | |
| 1107 return true; | |
| 1108 } else if (expression is PropertyAccess) { | |
| 1109 element = expression.propertyName.staticElement; | |
| 1110 } else if (expression is Identifier) { | |
| 1111 element = expression.staticElement; | |
| 1112 } | |
| 1113 // First class functions and static methods, where we know the original | |
| 1114 // declaration, will have an exact type, so we know a downcast will fail. | |
| 1115 return element is FunctionElement || | |
| 1116 element is MethodElement && element.isStatic; | |
| 1117 } | |
| 1118 | |
| 1119 /// Checks for overriding declarations of fields and methods. This is used to | 1125 /// Checks for overriding declarations of fields and methods. This is used to |
| 1120 /// check overrides between classes and superclasses, interfaces, and mixin | 1126 /// check overrides between classes and superclasses, interfaces, and mixin |
| 1121 /// applications. | 1127 /// applications. |
| 1122 class _OverrideChecker { | 1128 class _OverrideChecker { |
| 1123 final StrongTypeSystemImpl rules; | 1129 final StrongTypeSystemImpl rules; |
| 1124 final TypeProvider _typeProvider; | 1130 final TypeProvider _typeProvider; |
| 1125 final CodeChecker _checker; | 1131 final CodeChecker _checker; |
| 1126 | 1132 |
| 1127 _OverrideChecker(CodeChecker checker) | 1133 _OverrideChecker(CodeChecker checker) |
| 1128 : _checker = checker, | 1134 : _checker = checker, |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1475 var visited = new Set<InterfaceType>(); | 1481 var visited = new Set<InterfaceType>(); |
| 1476 do { | 1482 do { |
| 1477 visited.add(current); | 1483 visited.add(current); |
| 1478 current.mixins.reversed.forEach( | 1484 current.mixins.reversed.forEach( |
| 1479 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1485 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1480 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1486 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1481 current = current.superclass; | 1487 current = current.superclass; |
| 1482 } while (!current.isObject && !visited.contains(current)); | 1488 } while (!current.isObject && !visited.contains(current)); |
| 1483 } | 1489 } |
| 1484 } | 1490 } |
| OLD | NEW |