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 |