| 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 |