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 |