| 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 |