Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1053)

Side by Side Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 2775863004: Add error checking for the immutable annotation (issue 27750) (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/dart/error/hint_codes.dart ('k') | pkg/analyzer/test/generated/hint_code_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698