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/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
(...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
693 node.getAncestor((AstNode node) => node is MethodDeclaration); | 693 node.getAncestor((AstNode node) => node is MethodDeclaration); |
694 if (decl == null) { | 694 if (decl == null) { |
695 _errorReporter.reportErrorForNode( | 695 _errorReporter.reportErrorForNode( |
696 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | 696 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, |
697 node, | 697 node, |
698 [node.methodName.toString(), definingClass.name]); | 698 [node.methodName.toString(), definingClass.name]); |
699 return; | 699 return; |
700 } | 700 } |
701 | 701 |
702 ClassElement invokingClass = decl.element?.enclosingElement; | 702 ClassElement invokingClass = decl.element?.enclosingElement; |
703 if (invokingClass != null) { | 703 if (!_hasSuperType(invokingClass, definingClass.type)) { |
704 if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) { | 704 _errorReporter.reportErrorForNode( |
705 _errorReporter.reportErrorForNode( | 705 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, |
706 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | 706 node, |
707 node, | 707 [node.methodName.toString(), definingClass.name]); |
708 [node.methodName.toString(), definingClass.name]); | |
709 } | |
710 } | 708 } |
711 } | 709 } |
712 | 710 |
713 /** | 711 /** |
714 * Produces a hint if the given identifier is a protected field or getter | 712 * Produces a hint if the given identifier is a protected field or getter |
715 * accessed outside a subclass. | 713 * accessed outside a subclass. |
716 */ | 714 */ |
717 void _checkForInvalidProtectedPropertyAccess(SimpleIdentifier identifier) { | 715 void _checkForInvalidProtectedPropertyAccess(SimpleIdentifier identifier) { |
718 if (identifier.inDeclarationContext()) { | 716 if (identifier.inDeclarationContext()) { |
719 return; | 717 return; |
720 } | 718 } |
721 Element element = identifier.bestElement; | 719 Element element = identifier.bestElement; |
722 if (element is PropertyAccessorElement && | 720 if (element is PropertyAccessorElement && |
723 element.enclosingElement is ClassElement && | 721 element.enclosingElement is ClassElement && |
724 (element.isProtected || element.variable.isProtected)) { | 722 (element.isProtected || element.variable.isProtected)) { |
725 ClassElement definingClass = element.enclosingElement; | 723 ClassElement definingClass = element.enclosingElement; |
726 ClassDeclaration accessingClass = | 724 ClassDeclaration accessingClass = |
727 identifier.getAncestor((AstNode node) => node is ClassDeclaration); | 725 identifier.getAncestor((AstNode node) => node is ClassDeclaration); |
728 | 726 |
729 if (accessingClass == null) { | 727 if (accessingClass == null) { |
730 _errorReporter.reportErrorForNode( | 728 _errorReporter.reportErrorForNode( |
731 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | 729 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, |
732 identifier, | 730 identifier, |
733 [identifier.name.toString(), definingClass.name]); | 731 [identifier.name.toString(), definingClass.name]); |
734 } else if (!_hasSuperClassOrMixin( | 732 } else if (!_hasSuperType(accessingClass.element, definingClass.type)) { |
735 accessingClass.element, definingClass.type)) { | |
736 _errorReporter.reportErrorForNode( | 733 _errorReporter.reportErrorForNode( |
737 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | 734 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, |
738 identifier, | 735 identifier, |
739 [identifier.name.toString(), definingClass.name]); | 736 [identifier.name.toString(), definingClass.name]); |
740 } | 737 } |
741 } | 738 } |
742 } | 739 } |
743 | 740 |
744 /** | 741 /** |
745 * Check that the imported library does not define a loadLibrary function. The
import has already | 742 * Check that the imported library does not define a loadLibrary function. The
import has already |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 _errorReporter.reportErrorForNode( | 952 _errorReporter.reportErrorForNode( |
956 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); | 953 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); |
957 return true; | 954 return true; |
958 } | 955 } |
959 } | 956 } |
960 } | 957 } |
961 return false; | 958 return false; |
962 } | 959 } |
963 | 960 |
964 /** | 961 /** |
| 962 * Check for situations where the result of a method or function is used, when |
| 963 * it returns 'void'. |
| 964 * |
| 965 * See [HintCode.USE_OF_VOID_RESULT]. |
| 966 */ |
| 967 void _checkForUseOfVoidResult(Expression expression) { |
| 968 // TODO(jwren) Many other situations of use could be covered. We currently |
| 969 // cover the cases var x = m() and x = m(), but we could also cover cases |
| 970 // such as m().x, m()[k], a + m(), f(m()), return m(). |
| 971 if (expression is MethodInvocation) { |
| 972 if (identical(expression.staticType, VoidTypeImpl.instance)) { |
| 973 SimpleIdentifier methodName = expression.methodName; |
| 974 _errorReporter.reportErrorForNode( |
| 975 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); |
| 976 } |
| 977 } |
| 978 } |
| 979 |
| 980 /** |
965 * Check for the passed class declaration for the | 981 * Check for the passed class declaration for the |
966 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | 982 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. |
967 * | 983 * |
968 * @param node the class declaration to check | 984 * @param node the class declaration to check |
969 * @return `true` if and only if a hint code is generated on the passed node | 985 * @return `true` if and only if a hint code is generated on the passed node |
970 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. | 986 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. |
971 */ | 987 */ |
972 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { | 988 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { |
973 // ClassElement classElement = node.element; | 989 // ClassElement classElement = node.element; |
974 // if (classElement == null) { | 990 // if (classElement == null) { |
975 // return false; | 991 // return false; |
976 // } | 992 // } |
977 // MethodElement equalsOperatorMethodElement = | 993 // MethodElement equalsOperatorMethodElement = |
978 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); | 994 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); |
979 // if (equalsOperatorMethodElement != null) { | 995 // if (equalsOperatorMethodElement != null) { |
980 // PropertyAccessorElement hashCodeElement = | 996 // PropertyAccessorElement hashCodeElement = |
981 // classElement.getGetter(_HASHCODE_GETTER_NAME); | 997 // classElement.getGetter(_HASHCODE_GETTER_NAME); |
982 // if (hashCodeElement == null) { | 998 // if (hashCodeElement == null) { |
983 // _errorReporter.reportErrorForNode( | 999 // _errorReporter.reportErrorForNode( |
984 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, | 1000 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, |
985 // node.name, | 1001 // node.name, |
986 // [classElement.displayName]); | 1002 // [classElement.displayName]); |
987 // return true; | 1003 // return true; |
988 // } | 1004 // } |
989 // } | 1005 // } |
990 // return false; | 1006 // return false; |
991 // } | 1007 // } |
992 | 1008 |
993 /** | |
994 * Check for situations where the result of a method or function is used, when | |
995 * it returns 'void'. | |
996 * | |
997 * See [HintCode.USE_OF_VOID_RESULT]. | |
998 */ | |
999 void _checkForUseOfVoidResult(Expression expression) { | |
1000 // TODO(jwren) Many other situations of use could be covered. We currently | |
1001 // cover the cases var x = m() and x = m(), but we could also cover cases | |
1002 // such as m().x, m()[k], a + m(), f(m()), return m(). | |
1003 if (expression is MethodInvocation) { | |
1004 if (identical(expression.staticType, VoidTypeImpl.instance)) { | |
1005 SimpleIdentifier methodName = expression.methodName; | |
1006 _errorReporter.reportErrorForNode( | |
1007 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); | |
1008 } | |
1009 } | |
1010 } | |
1011 | |
1012 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) { | 1009 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) { |
1013 List<ClassElement> seenClasses = <ClassElement>[]; | 1010 List<ClassElement> seenClasses = <ClassElement>[]; |
1014 while (element != null && !seenClasses.contains(element)) { | 1011 while (element != null && !seenClasses.contains(element)) { |
1015 if (element.type == type) { | 1012 if (element.type == type) { |
1016 return true; | 1013 return true; |
1017 } | 1014 } |
1018 | 1015 |
1019 if (element.mixins.any((InterfaceType t) => t == type)) { | 1016 if (element.mixins.any((InterfaceType t) => t == type)) { |
1020 return true; | 1017 return true; |
1021 } | 1018 } |
1022 | 1019 |
1023 seenClasses.add(element); | 1020 seenClasses.add(element); |
1024 element = element.supertype?.element; | 1021 element = element.supertype?.element; |
1025 } | 1022 } |
1026 | 1023 |
1027 return false; | 1024 return false; |
1028 } | 1025 } |
1029 | 1026 |
| 1027 bool _hasSuperType(ClassElement element, InterfaceType type) => |
| 1028 element != null && element.allSupertypes.contains(type); |
| 1029 |
1030 /** | 1030 /** |
1031 * Given a parenthesized expression, this returns the parent (or recursively g
rand-parent) of the | 1031 * Given a parenthesized expression, this returns the parent (or recursively g
rand-parent) of the |
1032 * expression that is a parenthesized expression, but whose parent is not a pa
renthesized | 1032 * expression that is a parenthesized expression, but whose parent is not a pa
renthesized |
1033 * expression. | 1033 * expression. |
1034 * | 1034 * |
1035 * For example given the code `(((e)))`: `(e) -> (((e)))`. | 1035 * For example given the code `(((e)))`: `(e) -> (((e)))`. |
1036 * | 1036 * |
1037 * @param parenthesizedExpression some expression whose parent is a parenthesi
zed expression | 1037 * @param parenthesizedExpression some expression whose parent is a parenthesi
zed expression |
1038 * @return the first parent or grand-parent that is a parenthesized expression
, that does not have | 1038 * @return the first parent or grand-parent that is a parenthesized expression
, that does not have |
1039 * a parenthesized expression parent | 1039 * a parenthesized expression parent |
(...skipping 9938 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10978 return null; | 10978 return null; |
10979 } | 10979 } |
10980 if (identical(node.staticElement, variable)) { | 10980 if (identical(node.staticElement, variable)) { |
10981 if (node.inSetterContext()) { | 10981 if (node.inSetterContext()) { |
10982 result = true; | 10982 result = true; |
10983 } | 10983 } |
10984 } | 10984 } |
10985 return null; | 10985 return null; |
10986 } | 10986 } |
10987 } | 10987 } |
OLD | NEW |