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/standard_resolution_map.dart'; | 11 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
12 import 'package:analyzer/dart/ast/token.dart' show TokenType; | 12 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
13 import 'package:analyzer/dart/ast/token.dart'; | 13 import 'package:analyzer/dart/ast/token.dart'; |
14 import 'package:analyzer/dart/ast/visitor.dart'; | 14 import 'package:analyzer/dart/ast/visitor.dart'; |
15 import 'package:analyzer/dart/element/element.dart'; | 15 import 'package:analyzer/dart/element/element.dart'; |
16 import 'package:analyzer/dart/element/type.dart'; | 16 import 'package:analyzer/dart/element/type.dart'; |
| 17 import 'package:analyzer/src/dart/element/element.dart'; |
17 import 'package:analyzer/src/dart/element/type.dart'; | 18 import 'package:analyzer/src/dart/element/type.dart'; |
18 import 'package:analyzer/src/error/codes.dart' show StrongModeCode; | 19 import 'package:analyzer/src/error/codes.dart' show StrongModeCode; |
19 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; | 20 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; |
20 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 21 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
21 import 'package:analyzer/src/generated/type_system.dart'; | 22 import 'package:analyzer/src/generated/type_system.dart'; |
| 23 import 'package:analyzer/src/summary/idl.dart'; |
22 | 24 |
23 import 'ast_properties.dart'; | 25 import 'ast_properties.dart'; |
24 | 26 |
25 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider], | 27 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider], |
26 /// gets the known static type of the expression. | 28 /// gets the known static type of the expression. |
27 /// | 29 /// |
28 /// Normally when we ask for an expression's type, we get the type of the | 30 /// Normally when we ask for an expression's type, we get the type of the |
29 /// storage slot that would contain it. For function types, this is necessarily | 31 /// storage slot that would contain it. For function types, this is necessarily |
30 /// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're | 32 /// a "fuzzy arrow" that treats `dynamic` as bottom. However, if we're |
31 /// interested in the expression's own type, it can often be a "strict arrow" | 33 /// interested in the expression's own type, it can often be a "strict arrow" |
32 /// because we know it evaluates to a specific, concrete function, and we can | 34 /// because we know it evaluates to a specific, concrete function, and we can |
33 /// treat "dynamic" as top for that case, which is more permissive. | 35 /// treat "dynamic" as top for that case, which is more permissive. |
34 DartType getDefiniteType( | 36 DartType getDefiniteType( |
35 Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) { | 37 Expression expression, TypeSystem typeSystem, TypeProvider typeProvider) { |
36 DartType type = expression.staticType ?? DynamicTypeImpl.instance; | 38 DartType type = expression.staticType ?? DynamicTypeImpl.instance; |
37 if (typeSystem is StrongTypeSystemImpl && | 39 if (typeSystem is StrongTypeSystemImpl && |
38 type is FunctionType && | 40 type is FunctionType && |
39 hasStrictArrow(expression)) { | 41 hasStrictArrow(expression)) { |
40 // Remove fuzzy arrow if possible. | 42 // Remove fuzzy arrow if possible. |
41 return typeSystem.functionTypeToConcreteType(type); | 43 return typeSystem.functionTypeToConcreteType(type); |
42 } | 44 } |
43 return type; | 45 return type; |
44 } | 46 } |
45 | 47 |
| 48 bool hasStrictArrow(Expression expression) { |
| 49 var element = _getKnownElement(expression); |
| 50 return element is FunctionElement || element is MethodElement; |
| 51 } |
| 52 |
46 DartType _elementType(Element e) { | 53 DartType _elementType(Element e) { |
47 if (e == null) { | 54 if (e == null) { |
48 // Malformed code - just return dynamic. | 55 // Malformed code - just return dynamic. |
49 return DynamicTypeImpl.instance; | 56 return DynamicTypeImpl.instance; |
50 } | 57 } |
51 return (e as dynamic).type; | 58 return (e as dynamic).type; |
52 } | 59 } |
53 | 60 |
54 Element _getKnownElement(Expression expression) { | 61 Element _getKnownElement(Expression expression) { |
55 if (expression is ParenthesizedExpression) { | 62 if (expression is ParenthesizedExpression) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 } | 98 } |
92 if (field.isSynthetic) return null; | 99 if (field.isSynthetic) return null; |
93 return field; | 100 return field; |
94 } | 101 } |
95 | 102 |
96 /// Looks up the declaration that matches [member] in [type] and returns it's | 103 /// Looks up the declaration that matches [member] in [type] and returns it's |
97 /// declared type. | 104 /// declared type. |
98 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) => | 105 FunctionType _getMemberType(InterfaceType type, ExecutableElement member) => |
99 _memberTypeGetter(member)(type); | 106 _memberTypeGetter(member)(type); |
100 | 107 |
101 bool hasStrictArrow(Expression expression) { | |
102 var element = _getKnownElement(expression); | |
103 return element is FunctionElement || element is MethodElement; | |
104 } | |
105 | |
106 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) { | 108 _MemberTypeGetter _memberTypeGetter(ExecutableElement member) { |
107 String memberName = member.name; | 109 String memberName = member.name; |
108 final isGetter = member is PropertyAccessorElement && member.isGetter; | 110 final isGetter = member is PropertyAccessorElement && member.isGetter; |
109 final isSetter = member is PropertyAccessorElement && member.isSetter; | 111 final isSetter = member is PropertyAccessorElement && member.isSetter; |
110 | 112 |
111 FunctionType f(InterfaceType type) { | 113 FunctionType f(InterfaceType type) { |
112 ExecutableElement baseMethod; | 114 ExecutableElement baseMethod; |
113 | 115 |
114 if (member.isPrivate) { | 116 if (member.isPrivate) { |
115 var subtypeLibrary = member.library; | 117 var subtypeLibrary = member.library; |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 | 423 |
422 @override | 424 @override |
423 void visitForStatement(ForStatement node) { | 425 void visitForStatement(ForStatement node) { |
424 if (node.condition != null) { | 426 if (node.condition != null) { |
425 checkBoolean(node.condition); | 427 checkBoolean(node.condition); |
426 } | 428 } |
427 node.visitChildren(this); | 429 node.visitChildren(this); |
428 } | 430 } |
429 | 431 |
430 @override | 432 @override |
431 void visitFunctionExpression(FunctionExpression node) { | |
432 _checkForUnsafeBlockClosureInference(node); | |
433 super.visitFunctionExpression(node); | |
434 } | |
435 | |
436 @override | |
437 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 433 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
438 checkFunctionApplication(node); | 434 checkFunctionApplication(node); |
439 node.visitChildren(this); | 435 node.visitChildren(this); |
440 } | 436 } |
441 | 437 |
442 @override | 438 @override |
443 void visitIfStatement(IfStatement node) { | 439 void visitIfStatement(IfStatement node) { |
444 checkBoolean(node.condition); | 440 checkBoolean(node.condition); |
445 node.visitChildren(this); | 441 node.visitChildren(this); |
446 } | 442 } |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
638 : resolutionMap.elementDeclaredByVariableDeclaration(node); | 634 : resolutionMap.elementDeclaredByVariableDeclaration(node); |
639 if (!node.isConst && | 635 if (!node.isConst && |
640 !node.isFinal && | 636 !node.isFinal && |
641 node.initializer == null && | 637 node.initializer == null && |
642 rules.isNonNullableType(variableElement?.type)) { | 638 rules.isNonNullableType(variableElement?.type)) { |
643 _recordMessage( | 639 _recordMessage( |
644 node, | 640 node, |
645 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED, | 641 StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED, |
646 [node.name, variableElement?.type]); | 642 [node.name, variableElement?.type]); |
647 } | 643 } |
| 644 AstNode parent = node.parent; |
| 645 if (variableElement != null && |
| 646 parent is VariableDeclarationList && |
| 647 parent.type == null && |
| 648 node.initializer != null) { |
| 649 if (variableElement.kind == ElementKind.TOP_LEVEL_VARIABLE || |
| 650 variableElement.kind == ElementKind.FIELD) { |
| 651 _validateTopLevelInitializer(variableElement.name, node.initializer); |
| 652 } |
| 653 } |
648 return super.visitVariableDeclaration(node); | 654 return super.visitVariableDeclaration(node); |
649 } | 655 } |
650 | 656 |
651 @override | 657 @override |
652 void visitVariableDeclarationList(VariableDeclarationList node) { | 658 void visitVariableDeclarationList(VariableDeclarationList node) { |
653 TypeAnnotation type = node.type; | 659 TypeAnnotation type = node.type; |
654 if (type == null) { | 660 if (type == null) { |
655 // No checks are needed when the type is var. Although internally the | 661 // No checks are needed when the type is var. Although internally the |
656 // typing rules may have inferred a more precise type for the variable | 662 // typing rules may have inferred a more precise type for the variable |
657 // based on the initializer. | 663 // based on the initializer. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 } | 723 } |
718 | 724 |
719 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { | 725 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { |
720 if (field.staticElement == null && | 726 if (field.staticElement == null && |
721 !typeProvider.isObjectMember(field.name)) { | 727 !typeProvider.isObjectMember(field.name)) { |
722 _recordDynamicInvoke(node, target); | 728 _recordDynamicInvoke(node, target); |
723 } | 729 } |
724 node.visitChildren(this); | 730 node.visitChildren(this); |
725 } | 731 } |
726 | 732 |
727 /** | |
728 * Check if the closure [node] is unsafe due to dartbug.com/26947. If so, | |
729 * issue a warning. | |
730 * | |
731 * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed. | |
732 */ | |
733 void _checkForUnsafeBlockClosureInference(FunctionExpression node) { | |
734 if (node.body is! BlockFunctionBody) { | |
735 return; | |
736 } | |
737 if (resolutionMap | |
738 .elementDeclaredByFunctionExpression(node) | |
739 .returnType | |
740 .isDynamic) { | |
741 return; | |
742 } | |
743 // Find the enclosing variable declaration whose inferred type might depend | |
744 // on the inferred return type of the block closure (if any). | |
745 AstNode prevAncestor = node; | |
746 AstNode ancestor = node.parent; | |
747 while (ancestor != null && ancestor is! VariableDeclaration) { | |
748 if (ancestor is BlockFunctionBody) { | |
749 // node is inside another block function body; if that block | |
750 // function body is unsafe, we've already warned about it. | |
751 return; | |
752 } | |
753 if (ancestor is InstanceCreationExpression) { | |
754 // node appears inside an instance creation expression; we may be safe | |
755 // if the type of the instance creation expression requires no | |
756 // inference. | |
757 TypeName typeName = ancestor.constructorName.type; | |
758 if (typeName.typeArguments != null) { | |
759 // Type arguments were explicitly specified. We are safe. | |
760 return; | |
761 } | |
762 DartType type = typeName.type; | |
763 if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) { | |
764 // Type is not generic. We are safe. | |
765 return; | |
766 } | |
767 } | |
768 if (ancestor is MethodInvocation) { | |
769 // node appears inside a method or function invocation; we may be safe | |
770 // if the type of the method or function requires no inference. | |
771 if (ancestor.typeArguments != null) { | |
772 // Type arguments were explicitly specified. We are safe. | |
773 return; | |
774 } | |
775 Element methodElement = ancestor.methodName.staticElement; | |
776 if (!(methodElement is ExecutableElement && | |
777 methodElement.typeParameters.isNotEmpty)) { | |
778 // Method is not generic. We are safe. | |
779 return; | |
780 } | |
781 } | |
782 if (ancestor is FunctionExpressionInvocation && | |
783 !identical(prevAncestor, ancestor.function)) { | |
784 // node appears inside an argument to a function expression invocation; | |
785 // we may be safe if the type of the function expression requires no | |
786 // inference. | |
787 if (ancestor.typeArguments != null) { | |
788 // Type arguments were explicitly specified. We are safe. | |
789 return; | |
790 } | |
791 DartType type = ancestor.function.staticType; | |
792 if (!(type is FunctionTypeImpl && type.typeFormals.isNotEmpty)) { | |
793 // Type is not generic or has had its type parameters instantiated. | |
794 // We are safe. | |
795 return; | |
796 } | |
797 } | |
798 if ((ancestor is ListLiteral && ancestor.typeArguments != null) || | |
799 (ancestor is MapLiteral && ancestor.typeArguments != null)) { | |
800 // node appears inside a list or map literal with an explicit type. We | |
801 // are safe because no type inference is required. | |
802 return; | |
803 } | |
804 prevAncestor = ancestor; | |
805 ancestor = ancestor.parent; | |
806 } | |
807 if (ancestor == null) { | |
808 // node is not inside a variable declaration, so it is safe. | |
809 return; | |
810 } | |
811 VariableDeclaration decl = ancestor; | |
812 VariableElement declElement = decl.element; | |
813 if (!declElement.hasImplicitType) { | |
814 // Variable declaration has an explicit type, so it's safe. | |
815 return; | |
816 } | |
817 if (declElement.type.isDynamic) { | |
818 // No type was successfully inferred for this variable, so it's safe. | |
819 return; | |
820 } | |
821 if (declElement.enclosingElement is ExecutableElement) { | |
822 // Variable declaration is inside a function or method, so it's safe. | |
823 return; | |
824 } | |
825 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, | |
826 [declElement.name]); | |
827 } | |
828 | |
829 /// Checks if an implicit cast of [expr] from [from] type to [to] type is | 733 /// Checks if an implicit cast of [expr] from [from] type to [to] type is |
830 /// needed, and if so records it. | 734 /// needed, and if so records it. |
831 /// | 735 /// |
832 /// If [from] is omitted, uses the static type of [expr]. | 736 /// If [from] is omitted, uses the static type of [expr]. |
833 /// | 737 /// |
834 /// If [expr] does not require an implicit cast because it is not related to | 738 /// If [expr] does not require an implicit cast because it is not related to |
835 /// [to] or is already a subtype of it, does nothing. | 739 /// [to] or is already a subtype of it, does nothing. |
836 void _checkImplicitCast(Expression expr, DartType to, | 740 void _checkImplicitCast(Expression expr, DartType to, |
837 {DartType from, bool opAssign: false}) { | 741 {DartType from, bool opAssign: false}) { |
838 from ??= _getDefiniteType(expr); | 742 from ??= _getDefiniteType(expr); |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 : node.offset; | 1046 : node.offset; |
1143 int length = node.end - begin; | 1047 int length = node.end - begin; |
1144 var source = resolutionMap | 1048 var source = resolutionMap |
1145 .elementDeclaredByCompilationUnit(node.root as CompilationUnit) | 1049 .elementDeclaredByCompilationUnit(node.root as CompilationUnit) |
1146 .source; | 1050 .source; |
1147 var error = | 1051 var error = |
1148 new AnalysisError(source, begin, length, errorCode, arguments); | 1052 new AnalysisError(source, begin, length, errorCode, arguments); |
1149 reporter.onError(error); | 1053 reporter.onError(error); |
1150 } | 1054 } |
1151 } | 1055 } |
| 1056 |
| 1057 void _validateTopLevelInitializer(String name, Expression n) { |
| 1058 void validateHasType(PropertyAccessorElement e) { |
| 1059 if (e.hasImplicitReturnType) { |
| 1060 var variable = e.variable as VariableElementImpl; |
| 1061 TopLevelInferenceError error = variable.typeInferenceError; |
| 1062 if (error != null) { |
| 1063 if (error.kind == TopLevelInferenceErrorKind.dependencyCycle) { |
| 1064 _recordMessage( |
| 1065 n, StrongModeCode.TOP_LEVEL_CYCLE, [name, error.arguments]); |
| 1066 } else { |
| 1067 _recordMessage( |
| 1068 n, StrongModeCode.TOP_LEVEL_IDENTIFIER_NO_TYPE, [name, e.name]); |
| 1069 } |
| 1070 } |
| 1071 } |
| 1072 } |
| 1073 |
| 1074 void validateIdentifierElement(AstNode n, Element e) { |
| 1075 if (e == null) { |
| 1076 return; |
| 1077 } |
| 1078 |
| 1079 Element enclosing = e.enclosingElement; |
| 1080 if (enclosing is CompilationUnitElement) { |
| 1081 if (e is PropertyAccessorElement) { |
| 1082 validateHasType(e); |
| 1083 } |
| 1084 } else if (enclosing is ClassElement) { |
| 1085 if (e is PropertyAccessorElement) { |
| 1086 if (e.isStatic) { |
| 1087 validateHasType(e); |
| 1088 } else { |
| 1089 _recordMessage( |
| 1090 n, StrongModeCode.TOP_LEVEL_INSTANCE_GETTER, [name, e.name]); |
| 1091 } |
| 1092 } |
| 1093 } |
| 1094 } |
| 1095 |
| 1096 if (n == null || |
| 1097 n is NullLiteral || |
| 1098 n is BooleanLiteral || |
| 1099 n is DoubleLiteral || |
| 1100 n is IntegerLiteral || |
| 1101 n is StringLiteral || |
| 1102 n is SymbolLiteral) { |
| 1103 // Nothing to validate. |
| 1104 } else if (n is AwaitExpression) { |
| 1105 _validateTopLevelInitializer(name, n.expression); |
| 1106 } else if (n is ThrowExpression) { |
| 1107 // Nothing to validate. |
| 1108 } else if (n is ParenthesizedExpression) { |
| 1109 _validateTopLevelInitializer(name, n.expression); |
| 1110 } else if (n is ConditionalExpression) { |
| 1111 _validateTopLevelInitializer(name, n.thenExpression); |
| 1112 _validateTopLevelInitializer(name, n.elseExpression); |
| 1113 } else if (n is BinaryExpression) { |
| 1114 TokenType operator = n.operator.type; |
| 1115 if (operator == TokenType.AMPERSAND_AMPERSAND || |
| 1116 operator == TokenType.BAR_BAR || |
| 1117 operator == TokenType.EQ_EQ || |
| 1118 operator == TokenType.BANG_EQ) { |
| 1119 // These operators give 'bool', no need to validate operands. |
| 1120 } else if (operator == TokenType.QUESTION_QUESTION) { |
| 1121 _recordMessage(n, StrongModeCode.TOP_LEVEL_UNSUPPORTED, |
| 1122 [name, n.runtimeType.toString()]); |
| 1123 } else { |
| 1124 _validateTopLevelInitializer(name, n.leftOperand); |
| 1125 } |
| 1126 } else if (n is PrefixExpression) { |
| 1127 TokenType operator = n.operator.type; |
| 1128 if (operator == TokenType.BANG) { |
| 1129 // This operator gives 'bool', no need to validate operands. |
| 1130 } else { |
| 1131 _validateTopLevelInitializer(name, n.operand); |
| 1132 } |
| 1133 } else if (n is PostfixExpression) { |
| 1134 _validateTopLevelInitializer(name, n.operand); |
| 1135 } else if (n is ListLiteral) { |
| 1136 if (n.typeArguments == null) { |
| 1137 for (Expression element in n.elements) { |
| 1138 _validateTopLevelInitializer(name, element); |
| 1139 } |
| 1140 } |
| 1141 } else if (n is MapLiteral) { |
| 1142 if (n.typeArguments == null) { |
| 1143 for (MapLiteralEntry entry in n.entries) { |
| 1144 _validateTopLevelInitializer(name, entry.key); |
| 1145 _validateTopLevelInitializer(name, entry.value); |
| 1146 } |
| 1147 } |
| 1148 } else if (n is FunctionExpression) { |
| 1149 for (FormalParameter p in n.parameters.parameters) { |
| 1150 if (p is DefaultFormalParameter) { |
| 1151 p = (p as DefaultFormalParameter).parameter; |
| 1152 } |
| 1153 if (p is SimpleFormalParameter) { |
| 1154 if (p.type == null) { |
| 1155 _recordMessage( |
| 1156 p, |
| 1157 StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_PARAMETER, |
| 1158 [name, p.element?.name]); |
| 1159 } |
| 1160 } |
| 1161 } |
| 1162 |
| 1163 FunctionBody body = n.body; |
| 1164 if (body is ExpressionFunctionBody) { |
| 1165 _validateTopLevelInitializer(name, body.expression); |
| 1166 } else { |
| 1167 _recordMessage(n, StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK, []); |
| 1168 } |
| 1169 } else if (n is InstanceCreationExpression) { |
| 1170 ConstructorElement constructor = n.staticElement; |
| 1171 ClassElement clazz = constructor?.enclosingElement; |
| 1172 if (clazz != null && clazz.typeParameters.isNotEmpty) { |
| 1173 TypeName type = n.constructorName.type; |
| 1174 if (type.typeArguments == null) { |
| 1175 _recordMessage(type, StrongModeCode.TOP_LEVEL_TYPE_ARGUMENTS, |
| 1176 [name, clazz.name]); |
| 1177 } |
| 1178 } |
| 1179 } else if (n is AsExpression) { |
| 1180 // Nothing to validate. |
| 1181 } else if (n is IsExpression) { |
| 1182 // Nothing to validate. |
| 1183 } else if (n is Identifier) { |
| 1184 validateIdentifierElement(n, n.staticElement); |
| 1185 } else if (n is PropertyAccess) { |
| 1186 Element element = n.propertyName.staticElement; |
| 1187 validateIdentifierElement(n.propertyName, element); |
| 1188 } else if (n is FunctionExpressionInvocation) { |
| 1189 _validateTopLevelInitializer(name, n.function); |
| 1190 // TODO(scheglov) type arguments |
| 1191 } else if (n is MethodInvocation) { |
| 1192 _validateTopLevelInitializer(name, n.target); |
| 1193 SimpleIdentifier methodName = n.methodName; |
| 1194 Element element = methodName.staticElement; |
| 1195 if (element is ExecutableElement && element.typeParameters.isNotEmpty) { |
| 1196 if (n.typeArguments == null) { |
| 1197 _recordMessage(methodName, StrongModeCode.TOP_LEVEL_TYPE_ARGUMENTS, |
| 1198 [name, methodName.name]); |
| 1199 } |
| 1200 } |
| 1201 } else if (n is CascadeExpression) { |
| 1202 _validateTopLevelInitializer(name, n.target); |
| 1203 } else { |
| 1204 _recordMessage(n, StrongModeCode.TOP_LEVEL_UNSUPPORTED, |
| 1205 [name, n.runtimeType.toString()]); |
| 1206 } |
| 1207 } |
1152 } | 1208 } |
1153 | 1209 |
1154 /// Checks for overriding declarations of fields and methods. This is used to | 1210 /// Checks for overriding declarations of fields and methods. This is used to |
1155 /// check overrides between classes and superclasses, interfaces, and mixin | 1211 /// check overrides between classes and superclasses, interfaces, and mixin |
1156 /// applications. | 1212 /// applications. |
1157 class _OverrideChecker { | 1213 class _OverrideChecker { |
1158 final StrongTypeSystemImpl rules; | 1214 final StrongTypeSystemImpl rules; |
1159 final CodeChecker _checker; | 1215 final CodeChecker _checker; |
1160 | 1216 |
1161 _OverrideChecker(CodeChecker checker) | 1217 _OverrideChecker(CodeChecker checker) |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1493 var visited = new Set<InterfaceType>(); | 1549 var visited = new Set<InterfaceType>(); |
1494 do { | 1550 do { |
1495 visited.add(current); | 1551 visited.add(current); |
1496 current.mixins.reversed.forEach( | 1552 current.mixins.reversed.forEach( |
1497 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1553 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
1498 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1554 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
1499 current = current.superclass; | 1555 current = current.superclass; |
1500 } while (!current.isObject && !visited.contains(current)); | 1556 } while (!current.isObject && !visited.contains(current)); |
1501 } | 1557 } |
1502 } | 1558 } |
OLD | NEW |