| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library analyzer.src.generated.error_verifier; | 5 library analyzer.src.generated.error_verifier; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import "dart:math" as math; | 8 import "dart:math" as math; |
| 9 | 9 |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 } | 574 } |
| 575 } | 575 } |
| 576 | 576 |
| 577 @override | 577 @override |
| 578 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | 578 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 579 _isInConstructorInitializer = true; | 579 _isInConstructorInitializer = true; |
| 580 try { | 580 try { |
| 581 SimpleIdentifier fieldName = node.fieldName; | 581 SimpleIdentifier fieldName = node.fieldName; |
| 582 Element staticElement = fieldName.staticElement; | 582 Element staticElement = fieldName.staticElement; |
| 583 _checkForInvalidField(node, fieldName, staticElement); | 583 _checkForInvalidField(node, fieldName, staticElement); |
| 584 _checkForFieldInitializerNotAssignable(node, staticElement); | 584 if (staticElement is FieldElement) { |
| 585 _checkForFieldInitializerNotAssignable(node, staticElement); |
| 586 } |
| 585 return super.visitConstructorFieldInitializer(node); | 587 return super.visitConstructorFieldInitializer(node); |
| 586 } finally { | 588 } finally { |
| 587 _isInConstructorInitializer = false; | 589 _isInConstructorInitializer = false; |
| 588 } | 590 } |
| 589 } | 591 } |
| 590 | 592 |
| 591 @override | 593 @override |
| 592 Object visitContinueStatement(ContinueStatement node) { | 594 Object visitContinueStatement(ContinueStatement node) { |
| 593 SimpleIdentifier labelNode = node.label; | 595 SimpleIdentifier labelNode = node.label; |
| 594 if (labelNode != null) { | 596 if (labelNode != null) { |
| (...skipping 1210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1805 * [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT], and | 1807 * [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT], and |
| 1806 * [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]. | 1808 * [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]. |
| 1807 */ | 1809 */ |
| 1808 bool _checkForAllMixinErrorCodes(WithClause withClause) { | 1810 bool _checkForAllMixinErrorCodes(WithClause withClause) { |
| 1809 if (withClause == null) { | 1811 if (withClause == null) { |
| 1810 return false; | 1812 return false; |
| 1811 } | 1813 } |
| 1812 bool problemReported = false; | 1814 bool problemReported = false; |
| 1813 for (TypeName mixinName in withClause.mixinTypes) { | 1815 for (TypeName mixinName in withClause.mixinTypes) { |
| 1814 DartType mixinType = mixinName.type; | 1816 DartType mixinType = mixinName.type; |
| 1815 if (mixinType is! InterfaceType) { | 1817 if (mixinType is InterfaceType) { |
| 1816 continue; | 1818 if (_checkForExtendsOrImplementsDisallowedClass( |
| 1817 } | 1819 mixinName, CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS)) { |
| 1818 if (_checkForExtendsOrImplementsDisallowedClass( | |
| 1819 mixinName, CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS)) { | |
| 1820 problemReported = true; | |
| 1821 } else { | |
| 1822 ClassElement mixinElement = (mixinType as InterfaceType).element; | |
| 1823 if (_checkForExtendsOrImplementsDeferredClass( | |
| 1824 mixinName, CompileTimeErrorCode.MIXIN_DEFERRED_CLASS)) { | |
| 1825 problemReported = true; | 1820 problemReported = true; |
| 1826 } | 1821 } else { |
| 1827 if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) { | 1822 ClassElement mixinElement = mixinType.element; |
| 1828 problemReported = true; | 1823 if (_checkForExtendsOrImplementsDeferredClass( |
| 1829 } | 1824 mixinName, CompileTimeErrorCode.MIXIN_DEFERRED_CLASS)) { |
| 1830 if (!enableSuperMixins && | 1825 problemReported = true; |
| 1831 _checkForMixinInheritsNotFromObject(mixinName, mixinElement)) { | 1826 } |
| 1832 problemReported = true; | 1827 if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) { |
| 1833 } | 1828 problemReported = true; |
| 1834 if (_checkForMixinReferencesSuper(mixinName, mixinElement)) { | 1829 } |
| 1835 problemReported = true; | 1830 if (!enableSuperMixins && |
| 1831 _checkForMixinInheritsNotFromObject(mixinName, mixinElement)) { |
| 1832 problemReported = true; |
| 1833 } |
| 1834 if (_checkForMixinReferencesSuper(mixinName, mixinElement)) { |
| 1835 problemReported = true; |
| 1836 } |
| 1836 } | 1837 } |
| 1837 } | 1838 } |
| 1838 } | 1839 } |
| 1839 return problemReported; | 1840 return problemReported; |
| 1840 } | 1841 } |
| 1841 | 1842 |
| 1842 /** | 1843 /** |
| 1843 * Check for errors related to the redirected constructors. | 1844 * Check for errors related to the redirected constructors. |
| 1844 * | 1845 * |
| 1845 * See [StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE], | 1846 * See [StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE], |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1915 * [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]. | 1916 * [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]. |
| 1916 */ | 1917 */ |
| 1917 void _checkForAllReturnStatementErrorCodes(ReturnStatement statement) { | 1918 void _checkForAllReturnStatementErrorCodes(ReturnStatement statement) { |
| 1918 FunctionType functionType = | 1919 FunctionType functionType = |
| 1919 _enclosingFunction == null ? null : _enclosingFunction.type; | 1920 _enclosingFunction == null ? null : _enclosingFunction.type; |
| 1920 DartType expectedReturnType = functionType == null | 1921 DartType expectedReturnType = functionType == null |
| 1921 ? DynamicTypeImpl.instance | 1922 ? DynamicTypeImpl.instance |
| 1922 : functionType.returnType; | 1923 : functionType.returnType; |
| 1923 Expression returnExpression = statement.expression; | 1924 Expression returnExpression = statement.expression; |
| 1924 // RETURN_IN_GENERATIVE_CONSTRUCTOR | 1925 // RETURN_IN_GENERATIVE_CONSTRUCTOR |
| 1925 bool isGenerativeConstructor = _enclosingFunction is ConstructorElement && | 1926 bool isGenerativeConstructor(ExecutableElement element) => |
| 1926 !(_enclosingFunction as ConstructorElement).isFactory; | 1927 element is ConstructorElement && !element.isFactory; |
| 1927 if (isGenerativeConstructor) { | 1928 if (isGenerativeConstructor(_enclosingFunction)) { |
| 1928 if (returnExpression == null) { | 1929 if (returnExpression == null) { |
| 1929 return; | 1930 return; |
| 1930 } | 1931 } |
| 1931 _errorReporter.reportErrorForNode( | 1932 _errorReporter.reportErrorForNode( |
| 1932 CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, | 1933 CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, |
| 1933 returnExpression); | 1934 returnExpression); |
| 1934 return; | 1935 return; |
| 1935 } | 1936 } |
| 1936 // RETURN_WITHOUT_VALUE | 1937 // RETURN_WITHOUT_VALUE |
| 1937 if (returnExpression == null) { | 1938 if (returnExpression == null) { |
| (...skipping 1333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3271 _errorReporter.reportErrorForNode( | 3272 _errorReporter.reportErrorForNode( |
| 3272 errorCode, typeName, [disallowedType.displayName]); | 3273 errorCode, typeName, [disallowedType.displayName]); |
| 3273 return true; | 3274 return true; |
| 3274 } | 3275 } |
| 3275 } | 3276 } |
| 3276 return false; | 3277 return false; |
| 3277 } | 3278 } |
| 3278 | 3279 |
| 3279 /** | 3280 /** |
| 3280 * Verify that the given constructor field [initializer] has compatible field | 3281 * Verify that the given constructor field [initializer] has compatible field |
| 3281 * and initializer expression types. The [staticElement] is the static element | 3282 * and initializer expression types. The [fieldElement] is the static element |
| 3282 * from the name in the [ConstructorFieldInitializer]. | 3283 * from the name in the [ConstructorFieldInitializer]. |
| 3283 * | 3284 * |
| 3284 * See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and | 3285 * See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and |
| 3285 * [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE]. | 3286 * [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE]. |
| 3286 */ | 3287 */ |
| 3287 void _checkForFieldInitializerNotAssignable( | 3288 void _checkForFieldInitializerNotAssignable( |
| 3288 ConstructorFieldInitializer initializer, Element staticElement) { | 3289 ConstructorFieldInitializer initializer, FieldElement fieldElement) { |
| 3289 // prepare field element | |
| 3290 if (staticElement is! FieldElement) { | |
| 3291 return; | |
| 3292 } | |
| 3293 FieldElement fieldElement = staticElement as FieldElement; | |
| 3294 // prepare field type | 3290 // prepare field type |
| 3295 DartType fieldType = fieldElement.type; | 3291 DartType fieldType = fieldElement.type; |
| 3296 // prepare expression type | 3292 // prepare expression type |
| 3297 Expression expression = initializer.expression; | 3293 Expression expression = initializer.expression; |
| 3298 if (expression == null) { | 3294 if (expression == null) { |
| 3299 return; | 3295 return; |
| 3300 } | 3296 } |
| 3301 // test the static type of the expression | 3297 // test the static type of the expression |
| 3302 DartType staticType = getStaticType(expression); | 3298 DartType staticType = getStaticType(expression); |
| 3303 if (staticType == null) { | 3299 if (staticType == null) { |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3733 // OK, in comment | 3729 // OK, in comment |
| 3734 if (_isInComment) { | 3730 if (_isInComment) { |
| 3735 return; | 3731 return; |
| 3736 } | 3732 } |
| 3737 // OK, target is a type | 3733 // OK, target is a type |
| 3738 if (typeReference != null) { | 3734 if (typeReference != null) { |
| 3739 return; | 3735 return; |
| 3740 } | 3736 } |
| 3741 // prepare member Element | 3737 // prepare member Element |
| 3742 Element element = name.staticElement; | 3738 Element element = name.staticElement; |
| 3743 if (element is! ExecutableElement) { | 3739 if (element is ExecutableElement) { |
| 3744 return; | 3740 // OK, top-level element |
| 3741 if (element.enclosingElement is! ClassElement) { |
| 3742 return; |
| 3743 } |
| 3744 // OK, instance member |
| 3745 if (!element.isStatic) { |
| 3746 return; |
| 3747 } |
| 3748 _errorReporter.reportErrorForNode( |
| 3749 StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, |
| 3750 name, |
| 3751 [name.name]); |
| 3745 } | 3752 } |
| 3746 ExecutableElement executableElement = element as ExecutableElement; | |
| 3747 // OK, top-level element | |
| 3748 if (executableElement.enclosingElement is! ClassElement) { | |
| 3749 return; | |
| 3750 } | |
| 3751 // OK, instance member | |
| 3752 if (!executableElement.isStatic) { | |
| 3753 return; | |
| 3754 } | |
| 3755 | |
| 3756 _errorReporter.reportErrorForNode( | |
| 3757 StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, | |
| 3758 name, | |
| 3759 [name.name]); | |
| 3760 } | 3753 } |
| 3761 | 3754 |
| 3762 /** | 3755 /** |
| 3763 * Check whether the given [executableElement] collides with the name of a | 3756 * Check whether the given [executableElement] collides with the name of a |
| 3764 * static method in one of its superclasses, and reports the appropriate | 3757 * static method in one of its superclasses, and reports the appropriate |
| 3765 * warning if it does. The [errorNameTarget] is the node to report problems | 3758 * warning if it does. The [errorNameTarget] is the node to report problems |
| 3766 * on. | 3759 * on. |
| 3767 * | 3760 * |
| 3768 * See [StaticTypeWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_ST
ATIC]. | 3761 * See [StaticTypeWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_ST
ATIC]. |
| 3769 */ | 3762 */ |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4086 * Check to make sure that all similarly typed accessors are of the same type | 4079 * Check to make sure that all similarly typed accessors are of the same type |
| 4087 * (including inherited accessors). | 4080 * (including inherited accessors). |
| 4088 * | 4081 * |
| 4089 * See [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES], and | 4082 * See [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES], and |
| 4090 * [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE]. | 4083 * [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE]. |
| 4091 */ | 4084 */ |
| 4092 void _checkForMismatchedAccessorTypes( | 4085 void _checkForMismatchedAccessorTypes( |
| 4093 Declaration accessorDeclaration, String accessorTextName) { | 4086 Declaration accessorDeclaration, String accessorTextName) { |
| 4094 ExecutableElement accessorElement = | 4087 ExecutableElement accessorElement = |
| 4095 accessorDeclaration.element as ExecutableElement; | 4088 accessorDeclaration.element as ExecutableElement; |
| 4096 if (accessorElement is! PropertyAccessorElement) { | 4089 if (accessorElement is PropertyAccessorElement) { |
| 4097 return; | 4090 PropertyAccessorElement counterpartAccessor = null; |
| 4098 } | 4091 ClassElement enclosingClassForCounterpart = null; |
| 4099 PropertyAccessorElement propertyAccessorElement = | 4092 if (accessorElement.isGetter) { |
| 4100 accessorElement as PropertyAccessorElement; | 4093 counterpartAccessor = accessorElement.correspondingSetter; |
| 4101 PropertyAccessorElement counterpartAccessor = null; | 4094 } else { |
| 4102 ClassElement enclosingClassForCounterpart = null; | 4095 counterpartAccessor = accessorElement.correspondingGetter; |
| 4103 if (propertyAccessorElement.isGetter) { | 4096 // If the setter and getter are in the same enclosing element, return, |
| 4104 counterpartAccessor = propertyAccessorElement.correspondingSetter; | 4097 // this prevents having MISMATCHED_GETTER_AND_SETTER_TYPES reported twic
e. |
| 4105 } else { | 4098 if (counterpartAccessor != null && |
| 4106 counterpartAccessor = propertyAccessorElement.correspondingGetter; | 4099 identical(counterpartAccessor.enclosingElement, |
| 4107 // If the setter and getter are in the same enclosing element, return, | 4100 accessorElement.enclosingElement)) { |
| 4108 // this prevents having MISMATCHED_GETTER_AND_SETTER_TYPES reported twice. | 4101 return; |
| 4109 if (counterpartAccessor != null && | |
| 4110 identical(counterpartAccessor.enclosingElement, | |
| 4111 propertyAccessorElement.enclosingElement)) { | |
| 4112 return; | |
| 4113 } | |
| 4114 } | |
| 4115 if (counterpartAccessor == null) { | |
| 4116 // If the accessor is declared in a class, check the superclasses. | |
| 4117 if (_enclosingClass != null) { | |
| 4118 // Figure out the correct identifier to lookup in the inheritance graph, | |
| 4119 // if 'x', then 'x=', or if 'x=', then 'x'. | |
| 4120 String lookupIdentifier = propertyAccessorElement.name; | |
| 4121 if (StringUtilities.endsWithChar(lookupIdentifier, 0x3D)) { | |
| 4122 lookupIdentifier = | |
| 4123 lookupIdentifier.substring(0, lookupIdentifier.length - 1); | |
| 4124 } else { | |
| 4125 lookupIdentifier += "="; | |
| 4126 } | |
| 4127 // lookup with the identifier. | |
| 4128 ExecutableElement elementFromInheritance = _inheritanceManager | |
| 4129 .lookupInheritance(_enclosingClass, lookupIdentifier); | |
| 4130 // Verify that we found something, and that it is an accessor | |
| 4131 if (elementFromInheritance != null && | |
| 4132 elementFromInheritance is PropertyAccessorElement) { | |
| 4133 enclosingClassForCounterpart = | |
| 4134 elementFromInheritance.enclosingElement as ClassElement; | |
| 4135 counterpartAccessor = elementFromInheritance; | |
| 4136 } | 4102 } |
| 4137 } | 4103 } |
| 4138 if (counterpartAccessor == null) { | 4104 if (counterpartAccessor == null) { |
| 4139 return; | 4105 // If the accessor is declared in a class, check the superclasses. |
| 4106 if (_enclosingClass != null) { |
| 4107 // Figure out the correct identifier to lookup in the inheritance grap
h, |
| 4108 // if 'x', then 'x=', or if 'x=', then 'x'. |
| 4109 String lookupIdentifier = accessorElement.name; |
| 4110 if (StringUtilities.endsWithChar(lookupIdentifier, 0x3D)) { |
| 4111 lookupIdentifier = |
| 4112 lookupIdentifier.substring(0, lookupIdentifier.length - 1); |
| 4113 } else { |
| 4114 lookupIdentifier += "="; |
| 4115 } |
| 4116 // lookup with the identifier. |
| 4117 ExecutableElement elementFromInheritance = _inheritanceManager |
| 4118 .lookupInheritance(_enclosingClass, lookupIdentifier); |
| 4119 // Verify that we found something, and that it is an accessor |
| 4120 if (elementFromInheritance != null && |
| 4121 elementFromInheritance is PropertyAccessorElement) { |
| 4122 enclosingClassForCounterpart = |
| 4123 elementFromInheritance.enclosingElement as ClassElement; |
| 4124 counterpartAccessor = elementFromInheritance; |
| 4125 } |
| 4126 } |
| 4127 if (counterpartAccessor == null) { |
| 4128 return; |
| 4129 } |
| 4140 } | 4130 } |
| 4141 } | 4131 // Default of null == no accessor or no type (dynamic) |
| 4142 // Default of null == no accessor or no type (dynamic) | 4132 DartType getterType = null; |
| 4143 DartType getterType = null; | 4133 DartType setterType = null; |
| 4144 DartType setterType = null; | 4134 // Get an existing counterpart accessor if any. |
| 4145 // Get an existing counterpart accessor if any. | 4135 if (accessorElement.isGetter) { |
| 4146 if (propertyAccessorElement.isGetter) { | 4136 getterType = _getGetterType(accessorElement); |
| 4147 getterType = _getGetterType(propertyAccessorElement); | 4137 setterType = _getSetterType(counterpartAccessor); |
| 4148 setterType = _getSetterType(counterpartAccessor); | 4138 } else if (accessorElement.isSetter) { |
| 4149 } else if (propertyAccessorElement.isSetter) { | 4139 setterType = _getSetterType(accessorElement); |
| 4150 setterType = _getSetterType(propertyAccessorElement); | 4140 getterType = _getGetterType(counterpartAccessor); |
| 4151 getterType = _getGetterType(counterpartAccessor); | 4141 } |
| 4152 } | 4142 // If either types are not assignable to each other, report an error |
| 4153 // If either types are not assignable to each other, report an error | 4143 // (if the getter is null, it is dynamic which is assignable to everything
). |
| 4154 // (if the getter is null, it is dynamic which is assignable to everything). | 4144 if (setterType != null && |
| 4155 if (setterType != null && | 4145 getterType != null && |
| 4156 getterType != null && | 4146 !_typeSystem.isAssignableTo(getterType, setterType)) { |
| 4157 !_typeSystem.isAssignableTo(getterType, setterType)) { | 4147 if (enclosingClassForCounterpart == null) { |
| 4158 if (enclosingClassForCounterpart == null) { | 4148 _errorReporter.reportTypeErrorForNode( |
| 4159 _errorReporter.reportTypeErrorForNode( | 4149 StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES, |
| 4160 StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES, | 4150 accessorDeclaration, |
| 4161 accessorDeclaration, | 4151 [accessorTextName, setterType, getterType]); |
| 4162 [accessorTextName, setterType, getterType]); | 4152 } else { |
| 4163 } else { | 4153 _errorReporter.reportTypeErrorForNode( |
| 4164 _errorReporter.reportTypeErrorForNode( | 4154 StaticWarningCode |
| 4165 StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, | 4155 .MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, |
| 4166 accessorDeclaration, [ | 4156 accessorDeclaration, |
| 4167 accessorTextName, | 4157 [ |
| 4168 setterType, | 4158 accessorTextName, |
| 4169 getterType, | 4159 setterType, |
| 4170 enclosingClassForCounterpart.displayName | 4160 getterType, |
| 4171 ]); | 4161 enclosingClassForCounterpart.displayName |
| 4162 ]); |
| 4163 } |
| 4172 } | 4164 } |
| 4173 } | 4165 } |
| 4174 } | 4166 } |
| 4175 | 4167 |
| 4176 /** | 4168 /** |
| 4177 * Check to make sure that the given switch [statement] whose static type is | 4169 * Check to make sure that the given switch [statement] whose static type is |
| 4178 * an enum type either have a default case or include all of the enum | 4170 * an enum type either have a default case or include all of the enum |
| 4179 * constants. | 4171 * constants. |
| 4180 */ | 4172 */ |
| 4181 void _checkForMissingEnumConstantInSwitch(SwitchStatement statement) { | 4173 void _checkForMissingEnumConstantInSwitch(SwitchStatement statement) { |
| 4182 // TODO(brianwilkerson) This needs to be checked after constant values have | 4174 // TODO(brianwilkerson) This needs to be checked after constant values have |
| 4183 // been computed. | 4175 // been computed. |
| 4184 Expression expression = statement.expression; | 4176 Expression expression = statement.expression; |
| 4185 DartType expressionType = getStaticType(expression); | 4177 DartType expressionType = getStaticType(expression); |
| 4186 if (expressionType == null) { | 4178 if (expressionType == null) { |
| 4187 return; | 4179 return; |
| 4188 } | 4180 } |
| 4189 Element expressionElement = expressionType.element; | 4181 Element expressionElement = expressionType.element; |
| 4190 if (expressionElement is! ClassElement) { | 4182 if (expressionElement is ClassElement) { |
| 4191 return; | 4183 if (!expressionElement.isEnum) { |
| 4192 } | |
| 4193 ClassElement classElement = expressionElement as ClassElement; | |
| 4194 if (!classElement.isEnum) { | |
| 4195 return; | |
| 4196 } | |
| 4197 List<String> constantNames = <String>[]; | |
| 4198 List<FieldElement> fields = classElement.fields; | |
| 4199 int fieldCount = fields.length; | |
| 4200 for (int i = 0; i < fieldCount; i++) { | |
| 4201 FieldElement field = fields[i]; | |
| 4202 if (field.isStatic && !field.isSynthetic) { | |
| 4203 constantNames.add(field.name); | |
| 4204 } | |
| 4205 } | |
| 4206 NodeList<SwitchMember> members = statement.members; | |
| 4207 int memberCount = members.length; | |
| 4208 for (int i = 0; i < memberCount; i++) { | |
| 4209 SwitchMember member = members[i]; | |
| 4210 if (member is SwitchDefault) { | |
| 4211 return; | 4184 return; |
| 4212 } | 4185 } |
| 4213 String constantName = _getConstantName((member as SwitchCase).expression); | 4186 List<String> constantNames = <String>[]; |
| 4214 if (constantName != null) { | 4187 List<FieldElement> fields = expressionElement.fields; |
| 4215 constantNames.remove(constantName); | 4188 int fieldCount = fields.length; |
| 4189 for (int i = 0; i < fieldCount; i++) { |
| 4190 FieldElement field = fields[i]; |
| 4191 if (field.isStatic && !field.isSynthetic) { |
| 4192 constantNames.add(field.name); |
| 4193 } |
| 4216 } | 4194 } |
| 4217 } | 4195 NodeList<SwitchMember> members = statement.members; |
| 4218 if (constantNames.isEmpty) { | 4196 int memberCount = members.length; |
| 4219 return; | 4197 for (int i = 0; i < memberCount; i++) { |
| 4220 } | 4198 SwitchMember member = members[i]; |
| 4221 for (int i = 0; i < constantNames.length; i++) { | 4199 if (member is SwitchDefault) { |
| 4222 int offset = statement.offset; | 4200 return; |
| 4223 int end = statement.rightParenthesis.end; | 4201 } |
| 4224 _errorReporter.reportErrorForOffset( | 4202 String constantName = |
| 4225 StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH, | 4203 _getConstantName((member as SwitchCase).expression); |
| 4226 offset, | 4204 if (constantName != null) { |
| 4227 end - offset, | 4205 constantNames.remove(constantName); |
| 4228 [constantNames[i]]); | 4206 } |
| 4207 } |
| 4208 if (constantNames.isEmpty) { |
| 4209 return; |
| 4210 } |
| 4211 for (int i = 0; i < constantNames.length; i++) { |
| 4212 int offset = statement.offset; |
| 4213 int end = statement.rightParenthesis.end; |
| 4214 _errorReporter.reportErrorForOffset( |
| 4215 StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH, |
| 4216 offset, |
| 4217 end - offset, |
| 4218 [constantNames[i]]); |
| 4219 } |
| 4229 } | 4220 } |
| 4230 } | 4221 } |
| 4231 | 4222 |
| 4232 void _checkForMissingJSLibAnnotation(Annotation node) { | 4223 void _checkForMissingJSLibAnnotation(Annotation node) { |
| 4233 if (node.elementAnnotation?.isJS ?? false) { | 4224 if (node.elementAnnotation?.isJS ?? false) { |
| 4234 Element element = ElementLocator.locate(node.parent); | 4225 Element element = ElementLocator.locate(node.parent); |
| 4235 if (element?.library?.isJS != true) { | 4226 if (element?.library?.isJS != true) { |
| 4236 _errorReporter.reportErrorForNode( | 4227 _errorReporter.reportErrorForNode( |
| 4237 HintCode.MISSING_JS_LIB_ANNOTATION, node, [element.name]); | 4228 HintCode.MISSING_JS_LIB_ANNOTATION, node, [element.name]); |
| 4238 } | 4229 } |
| (...skipping 882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5121 // OK, in comment | 5112 // OK, in comment |
| 5122 if (_isInComment) { | 5113 if (_isInComment) { |
| 5123 return; | 5114 return; |
| 5124 } | 5115 } |
| 5125 // OK, target is not a type | 5116 // OK, target is not a type |
| 5126 if (typeReference == null) { | 5117 if (typeReference == null) { |
| 5127 return; | 5118 return; |
| 5128 } | 5119 } |
| 5129 // prepare member Element | 5120 // prepare member Element |
| 5130 Element element = name.staticElement; | 5121 Element element = name.staticElement; |
| 5131 if (element is! ExecutableElement) { | 5122 if (element is ExecutableElement) { |
| 5132 return; | 5123 // OK, static |
| 5124 if (element.isStatic) { |
| 5125 return; |
| 5126 } |
| 5127 _errorReporter.reportErrorForNode( |
| 5128 StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, |
| 5129 name, |
| 5130 [name.name]); |
| 5133 } | 5131 } |
| 5134 ExecutableElement memberElement = element as ExecutableElement; | |
| 5135 // OK, static | |
| 5136 if (memberElement.isStatic) { | |
| 5137 return; | |
| 5138 } | |
| 5139 | |
| 5140 _errorReporter.reportErrorForNode( | |
| 5141 StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, name, [name.name]); | |
| 5142 } | 5132 } |
| 5143 | 5133 |
| 5144 /** | 5134 /** |
| 5145 * Check that the type of the expression in the given 'switch' [statement] is | 5135 * Check that the type of the expression in the given 'switch' [statement] is |
| 5146 * assignable to the type of the 'case' members. | 5136 * assignable to the type of the 'case' members. |
| 5147 * | 5137 * |
| 5148 * See [StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE]. | 5138 * See [StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE]. |
| 5149 */ | 5139 */ |
| 5150 void _checkForSwitchExpressionNotAssignable(SwitchStatement statement) { | 5140 void _checkForSwitchExpressionNotAssignable(SwitchStatement statement) { |
| 5151 // prepare 'switch' expression type | 5141 // prepare 'switch' expression type |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5210 if (typeName.typeArguments == null) { | 5200 if (typeName.typeArguments == null) { |
| 5211 return; | 5201 return; |
| 5212 } | 5202 } |
| 5213 // prepare Type | 5203 // prepare Type |
| 5214 DartType type = typeName.type; | 5204 DartType type = typeName.type; |
| 5215 if (type == null) { | 5205 if (type == null) { |
| 5216 return; | 5206 return; |
| 5217 } | 5207 } |
| 5218 // prepare ClassElement | 5208 // prepare ClassElement |
| 5219 Element element = type.element; | 5209 Element element = type.element; |
| 5220 if (element is! ClassElement) { | 5210 if (element is ClassElement) { |
| 5221 return; | 5211 // prepare type parameters |
| 5222 } | 5212 List<DartType> typeParameters = element.type.typeArguments; |
| 5223 ClassElement classElement = element as ClassElement; | 5213 List<TypeParameterElement> boundingElts = element.typeParameters; |
| 5224 // prepare type parameters | 5214 // iterate over each bounded type parameter and corresponding argument |
| 5225 List<DartType> typeParameters = classElement.type.typeArguments; | 5215 NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments; |
| 5226 List<TypeParameterElement> boundingElts = classElement.typeParameters; | 5216 List<DartType> typeArguments = (type as InterfaceType).typeArguments; |
| 5227 // iterate over each bounded type parameter and corresponding argument | 5217 int loopThroughIndex = |
| 5228 NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments; | 5218 math.min(typeNameArgList.length, boundingElts.length); |
| 5229 List<DartType> typeArguments = (type as InterfaceType).typeArguments; | |
| 5230 int loopThroughIndex = | |
| 5231 math.min(typeNameArgList.length, boundingElts.length); | |
| 5232 | 5219 |
| 5233 for (int i = 0; i < loopThroughIndex; i++) { | 5220 for (int i = 0; i < loopThroughIndex; i++) { |
| 5234 TypeName argTypeName = typeNameArgList[i]; | 5221 TypeName argTypeName = typeNameArgList[i]; |
| 5235 DartType argType = argTypeName.type; | 5222 DartType argType = argTypeName.type; |
| 5236 DartType boundType = boundingElts[i].bound; | 5223 DartType boundType = boundingElts[i].bound; |
| 5237 if (argType != null && boundType != null) { | 5224 if (argType != null && boundType != null) { |
| 5238 if (typeArguments.length != 0 && | 5225 if (typeArguments.length != 0 && |
| 5239 typeArguments.length == typeParameters.length) { | 5226 typeArguments.length == typeParameters.length) { |
| 5240 boundType = boundType.substitute2(typeArguments, typeParameters); | 5227 boundType = boundType.substitute2(typeArguments, typeParameters); |
| 5241 } | |
| 5242 if (!_typeSystem.isSubtypeOf(argType, boundType)) { | |
| 5243 ErrorCode errorCode; | |
| 5244 if (_isInConstInstanceCreation) { | |
| 5245 errorCode = CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
| 5246 } else { | |
| 5247 errorCode = StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
| 5248 } | 5228 } |
| 5249 _errorReporter.reportTypeErrorForNode( | 5229 if (!_typeSystem.isSubtypeOf(argType, boundType)) { |
| 5250 errorCode, argTypeName, [argType, boundType]); | 5230 ErrorCode errorCode; |
| 5231 if (_isInConstInstanceCreation) { |
| 5232 errorCode = |
| 5233 CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; |
| 5234 } else { |
| 5235 errorCode = |
| 5236 StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; |
| 5237 } |
| 5238 _errorReporter.reportTypeErrorForNode( |
| 5239 errorCode, argTypeName, [argType, boundType]); |
| 5240 } |
| 5251 } | 5241 } |
| 5252 } | 5242 } |
| 5253 } | 5243 } |
| 5254 } | 5244 } |
| 5255 | 5245 |
| 5256 /** | 5246 /** |
| 5257 * Check whether the given type [name] is a type parameter being used to | 5247 * Check whether the given type [name] is a type parameter being used to |
| 5258 * define a static member. | 5248 * define a static member. |
| 5259 * | 5249 * |
| 5260 * See [StaticWarningCode.TYPE_PARAMETER_REFERENCED_BY_STATIC]. | 5250 * See [StaticWarningCode.TYPE_PARAMETER_REFERENCED_BY_STATIC]. |
| (...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5898 * have to equal or be a subtype of the given executable element, this is due | 5888 * have to equal or be a subtype of the given executable element, this is due |
| 5899 * to the specific use where this method is used in | 5889 * to the specific use where this method is used in |
| 5900 * [_checkForNonAbstractClassInheritsAbstractMember]. | 5890 * [_checkForNonAbstractClassInheritsAbstractMember]. |
| 5901 */ | 5891 */ |
| 5902 bool _isMemberInClassOrMixin( | 5892 bool _isMemberInClassOrMixin( |
| 5903 ExecutableElement executableElement, ClassElement classElement) { | 5893 ExecutableElement executableElement, ClassElement classElement) { |
| 5904 ExecutableElement foundElt = null; | 5894 ExecutableElement foundElt = null; |
| 5905 String executableName = executableElement.name; | 5895 String executableName = executableElement.name; |
| 5906 if (executableElement is MethodElement) { | 5896 if (executableElement is MethodElement) { |
| 5907 foundElt = classElement.getMethod(executableName); | 5897 foundElt = classElement.getMethod(executableName); |
| 5908 if (foundElt != null && !(foundElt as MethodElement).isAbstract) { | 5898 if (foundElt != null && !foundElt.isAbstract) { |
| 5909 return true; | 5899 return true; |
| 5910 } | 5900 } |
| 5911 List<InterfaceType> mixins = classElement.mixins; | 5901 List<InterfaceType> mixins = classElement.mixins; |
| 5912 for (int i = 0; i < mixins.length && foundElt == null; i++) { | 5902 for (int i = 0; i < mixins.length && foundElt == null; i++) { |
| 5913 foundElt = mixins[i].getMethod(executableName); | 5903 foundElt = mixins[i].getMethod(executableName); |
| 5914 } | 5904 } |
| 5915 if (foundElt != null && !(foundElt as MethodElement).isAbstract) { | 5905 if (foundElt != null && !foundElt.isAbstract) { |
| 5916 return true; | 5906 return true; |
| 5917 } | 5907 } |
| 5918 } else if (executableElement is PropertyAccessorElement) { | 5908 } else if (executableElement is PropertyAccessorElement) { |
| 5919 if (executableElement.isGetter) { | 5909 if (executableElement.isGetter) { |
| 5920 foundElt = classElement.getGetter(executableName); | 5910 foundElt = classElement.getGetter(executableName); |
| 5921 } | 5911 } |
| 5922 if (foundElt == null && executableElement.isSetter) { | 5912 if (foundElt == null && executableElement.isSetter) { |
| 5923 foundElt = classElement.getSetter(executableName); | 5913 foundElt = classElement.getSetter(executableName); |
| 5924 } | 5914 } |
| 5925 if (foundElt != null && | 5915 if (foundElt != null && |
| 5926 !(foundElt as PropertyAccessorElement).isAbstract) { | 5916 !(foundElt as PropertyAccessorElement).isAbstract) { |
| 5927 return true; | 5917 return true; |
| 5928 } | 5918 } |
| 5929 List<InterfaceType> mixins = classElement.mixins; | 5919 List<InterfaceType> mixins = classElement.mixins; |
| 5930 for (int i = 0; i < mixins.length && foundElt == null; i++) { | 5920 for (int i = 0; i < mixins.length && foundElt == null; i++) { |
| 5931 foundElt = mixins[i].getGetter(executableName); | 5921 foundElt = mixins[i].getGetter(executableName); |
| 5932 if (foundElt == null) { | 5922 if (foundElt == null) { |
| 5933 foundElt = mixins[i].getSetter(executableName); | 5923 foundElt = mixins[i].getSetter(executableName); |
| 5934 } | 5924 } |
| 5935 } | 5925 } |
| 5936 if (foundElt != null && | 5926 if (foundElt != null && !foundElt.isAbstract) { |
| 5937 !(foundElt as PropertyAccessorElement).isAbstract) { | |
| 5938 return true; | 5927 return true; |
| 5939 } | 5928 } |
| 5940 } | 5929 } |
| 5941 return false; | 5930 return false; |
| 5942 } | 5931 } |
| 5943 | 5932 |
| 5944 /** | 5933 /** |
| 5945 * Return `true` if the given 'this' [expression] is in a valid context. | 5934 * Return `true` if the given 'this' [expression] is in a valid context. |
| 5946 */ | 5935 */ |
| 5947 bool _isThisInValidContext(ThisExpression expression) { | 5936 bool _isThisInValidContext(ThisExpression expression) { |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6149 class _InvocationCollector extends RecursiveAstVisitor { | 6138 class _InvocationCollector extends RecursiveAstVisitor { |
| 6150 final List<String> superCalls = <String>[]; | 6139 final List<String> superCalls = <String>[]; |
| 6151 | 6140 |
| 6152 @override | 6141 @override |
| 6153 visitMethodInvocation(MethodInvocation node) { | 6142 visitMethodInvocation(MethodInvocation node) { |
| 6154 if (node.target is SuperExpression) { | 6143 if (node.target is SuperExpression) { |
| 6155 superCalls.add(node.methodName.name); | 6144 superCalls.add(node.methodName.name); |
| 6156 } | 6145 } |
| 6157 } | 6146 } |
| 6158 } | 6147 } |
| OLD | NEW |