| 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.resolver; | 5 library analyzer.src.generated.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 this._currentLibrary, this._manager, | 101 this._currentLibrary, this._manager, |
| 102 {TypeSystem typeSystem}) | 102 {TypeSystem typeSystem}) |
| 103 : _nullType = typeProvider.nullType, | 103 : _nullType = typeProvider.nullType, |
| 104 _futureNullType = typeProvider.futureNullType, | 104 _futureNullType = typeProvider.futureNullType, |
| 105 _typeSystem = typeSystem ?? new TypeSystemImpl(typeProvider) { | 105 _typeSystem = typeSystem ?? new TypeSystemImpl(typeProvider) { |
| 106 inDeprecatedMember = _currentLibrary.isDeprecated; | 106 inDeprecatedMember = _currentLibrary.isDeprecated; |
| 107 } | 107 } |
| 108 | 108 |
| 109 @override | 109 @override |
| 110 Object visitAnnotation(Annotation node) { | 110 Object visitAnnotation(Annotation node) { |
| 111 if (resolutionMap.elementAnnotationForAnnotation(node)?.isFactory == true) { | 111 ElementAnnotation element = |
| 112 resolutionMap.elementAnnotationForAnnotation(node); |
| 113 if (element?.isFactory == true) { |
| 112 AstNode parent = node.parent; | 114 AstNode parent = node.parent; |
| 113 if (parent is MethodDeclaration) { | 115 if (parent is MethodDeclaration) { |
| 114 _checkForInvalidFactory(parent); | 116 _checkForInvalidFactory(parent); |
| 115 } else { | 117 } else { |
| 116 _errorReporter | 118 _errorReporter |
| 117 .reportErrorForNode(HintCode.INVALID_FACTORY_ANNOTATION, node, []); | 119 .reportErrorForNode(HintCode.INVALID_FACTORY_ANNOTATION, node, []); |
| 118 } | 120 } |
| 121 } else if (element?.isImmutable == true) { |
| 122 AstNode parent = node.parent; |
| 123 if (parent is! ClassDeclaration) { |
| 124 _errorReporter.reportErrorForNode( |
| 125 HintCode.INVALID_IMMUTABLE_ANNOTATION, node, []); |
| 126 } |
| 119 } | 127 } |
| 120 return super.visitAnnotation(node); | 128 return super.visitAnnotation(node); |
| 121 } | 129 } |
| 122 | 130 |
| 123 @override | 131 @override |
| 124 Object visitArgumentList(ArgumentList node) { | 132 Object visitArgumentList(ArgumentList node) { |
| 125 for (Expression argument in node.arguments) { | 133 for (Expression argument in node.arguments) { |
| 126 ParameterElement parameter = argument.bestParameterElement; | 134 ParameterElement parameter = argument.bestParameterElement; |
| 127 if (parameter?.parameterKind == ParameterKind.POSITIONAL) { | 135 if (parameter?.parameterKind == ParameterKind.POSITIONAL) { |
| 128 _checkForDeprecatedMemberUse(parameter, argument); | 136 _checkForDeprecatedMemberUse(parameter, argument); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 ClassElementImpl outerClass = _enclosingClass; | 182 ClassElementImpl outerClass = _enclosingClass; |
| 175 bool wasInDeprecatedMember = inDeprecatedMember; | 183 bool wasInDeprecatedMember = inDeprecatedMember; |
| 176 ClassElement element = AbstractClassElementImpl.getImpl(node.element); | 184 ClassElement element = AbstractClassElementImpl.getImpl(node.element); |
| 177 if (element != null && element.isDeprecated) { | 185 if (element != null && element.isDeprecated) { |
| 178 inDeprecatedMember = true; | 186 inDeprecatedMember = true; |
| 179 } | 187 } |
| 180 try { | 188 try { |
| 181 _enclosingClass = element; | 189 _enclosingClass = element; |
| 182 // Commented out until we decide that we want this hint in the analyzer | 190 // Commented out until we decide that we want this hint in the analyzer |
| 183 // checkForOverrideEqualsButNotHashCode(node); | 191 // checkForOverrideEqualsButNotHashCode(node); |
| 192 _checkForImmutable(node); |
| 184 return super.visitClassDeclaration(node); | 193 return super.visitClassDeclaration(node); |
| 185 } finally { | 194 } finally { |
| 186 _enclosingClass = outerClass; | 195 _enclosingClass = outerClass; |
| 187 inDeprecatedMember = wasInDeprecatedMember; | 196 inDeprecatedMember = wasInDeprecatedMember; |
| 188 } | 197 } |
| 189 } | 198 } |
| 190 | 199 |
| 191 @override | 200 @override |
| 192 Object visitConditionalExpression(ConditionalExpression node) { | 201 Object visitConditionalExpression(ConditionalExpression node) { |
| 193 _checkForPossibleNullCondition(node.condition); | 202 _checkForPossibleNullCondition(node.condition); |
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 grandParent.argumentList.arguments.isEmpty) { | 731 grandParent.argumentList.arguments.isEmpty) { |
| 723 _errorReporter.reportErrorForNode( | 732 _errorReporter.reportErrorForNode( |
| 724 HintCode.DIVISION_OPTIMIZATION, grandParent); | 733 HintCode.DIVISION_OPTIMIZATION, grandParent); |
| 725 return true; | 734 return true; |
| 726 } | 735 } |
| 727 } | 736 } |
| 728 } | 737 } |
| 729 return false; | 738 return false; |
| 730 } | 739 } |
| 731 | 740 |
| 741 void _checkForImmutable(ClassDeclaration node) { |
| 742 /** |
| 743 * Return `true` if the given class [element] is annotated with the |
| 744 * `@immutable` annotation. |
| 745 */ |
| 746 bool isImmutable(ClassElement element) { |
| 747 for (ElementAnnotation annotation in element.metadata) { |
| 748 if (annotation.isImmutable) { |
| 749 return true; |
| 750 } |
| 751 } |
| 752 return false; |
| 753 } |
| 754 |
| 755 /** |
| 756 * Return `true` if the given class [element] or any superclass of it is |
| 757 * annotated with the `@immutable` annotation. |
| 758 */ |
| 759 bool isOrInheritsImmutable( |
| 760 ClassElement element, HashSet<ClassElement> visited) { |
| 761 if (visited.add(element)) { |
| 762 if (isImmutable(element)) { |
| 763 return true; |
| 764 } |
| 765 for (InterfaceType interface in element.mixins) { |
| 766 if (isOrInheritsImmutable(interface.element, visited)) { |
| 767 return true; |
| 768 } |
| 769 } |
| 770 for (InterfaceType mixin in element.interfaces) { |
| 771 if (isOrInheritsImmutable(mixin.element, visited)) { |
| 772 return true; |
| 773 } |
| 774 } |
| 775 if (element.supertype != null) { |
| 776 return isOrInheritsImmutable(element.supertype.element, visited); |
| 777 } |
| 778 } |
| 779 return false; |
| 780 } |
| 781 |
| 782 /** |
| 783 * Return `true` if the given class [element] defines a non-final field. |
| 784 */ |
| 785 bool hasNonFinalField(ClassElement element) { |
| 786 for (FieldElement field in element.fields) { |
| 787 if (!field.isSynthetic && !field.isFinal) { |
| 788 return true; |
| 789 } |
| 790 } |
| 791 return false; |
| 792 } |
| 793 |
| 794 /** |
| 795 * Return `true` if the given class [element] defines or inherits a |
| 796 * non-final field. |
| 797 */ |
| 798 bool hasOrInheritsNonFinalField( |
| 799 ClassElement element, HashSet<ClassElement> visited) { |
| 800 if (visited.add(element)) { |
| 801 if (hasNonFinalField(element)) { |
| 802 return true; |
| 803 } |
| 804 for (InterfaceType mixin in element.mixins) { |
| 805 if (hasNonFinalField(mixin.element)) { |
| 806 return true; |
| 807 } |
| 808 } |
| 809 if (element.supertype != null) { |
| 810 return hasOrInheritsNonFinalField(element.supertype.element, visited); |
| 811 } |
| 812 } |
| 813 return false; |
| 814 } |
| 815 |
| 816 ClassElement element = node.element; |
| 817 if (isOrInheritsImmutable(element, new HashSet<ClassElement>()) && |
| 818 hasOrInheritsNonFinalField(element, new HashSet<ClassElement>())) { |
| 819 _errorReporter.reportErrorForNode(HintCode.MUST_BE_IMMUTABLE, node.name); |
| 820 } |
| 821 } |
| 822 |
| 732 /** | 823 /** |
| 733 * This verifies that the passed left hand side and right hand side represent
a valid assignment. | 824 * This verifies that the passed left hand side and right hand side represent
a valid assignment. |
| 734 * | 825 * |
| 735 * This method corresponds to ErrorVerifier.checkForInvalidAssignment. | 826 * This method corresponds to ErrorVerifier.checkForInvalidAssignment. |
| 736 * | 827 * |
| 737 * @param lhs the left hand side expression | 828 * @param lhs the left hand side expression |
| 738 * @param rhs the right hand side expression | 829 * @param rhs the right hand side expression |
| 739 * @return `true` if and only if an error code is generated on the passed node | 830 * @return `true` if and only if an error code is generated on the passed node |
| 740 * See [HintCode.INVALID_ASSIGNMENT]. | 831 * See [HintCode.INVALID_ASSIGNMENT]. |
| 741 */ | 832 */ |
| (...skipping 10063 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10805 return null; | 10896 return null; |
| 10806 } | 10897 } |
| 10807 if (identical(node.staticElement, variable)) { | 10898 if (identical(node.staticElement, variable)) { |
| 10808 if (node.inSetterContext()) { | 10899 if (node.inSetterContext()) { |
| 10809 result = true; | 10900 result = true; |
| 10810 } | 10901 } |
| 10811 } | 10902 } |
| 10812 return null; | 10903 return null; |
| 10813 } | 10904 } |
| 10814 } | 10905 } |
| OLD | NEW |