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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
199 // This was determined to not be a good hint, see: dartbug.com/16029 | 199 // This was determined to not be a good hint, see: dartbug.com/16029 |
200 //checkForOverridingPrivateMember(node); | 200 //checkForOverridingPrivateMember(node); |
201 _checkForMissingReturn(node.returnType, node.body); | 201 _checkForMissingReturn(node.returnType, node.body); |
202 _checkForUnnecessaryNoSuchMethod(node); | 202 _checkForUnnecessaryNoSuchMethod(node); |
203 return super.visitMethodDeclaration(node); | 203 return super.visitMethodDeclaration(node); |
204 } | 204 } |
205 | 205 |
206 @override | 206 @override |
207 Object visitMethodInvocation(MethodInvocation node) { | 207 Object visitMethodInvocation(MethodInvocation node) { |
208 _checkForCanBeNullAfterNullAware(node.realTarget, node.operator); | 208 _checkForCanBeNullAfterNullAware(node.realTarget, node.operator); |
209 _checkForInvalidProtectedMethodCalls(node); | |
209 return super.visitMethodInvocation(node); | 210 return super.visitMethodInvocation(node); |
210 } | 211 } |
211 | 212 |
212 @override | 213 @override |
213 Object visitPostfixExpression(PostfixExpression node) { | 214 Object visitPostfixExpression(PostfixExpression node) { |
214 _checkForDeprecatedMemberUse(node.bestElement, node); | 215 _checkForDeprecatedMemberUse(node.bestElement, node); |
215 return super.visitPostfixExpression(node); | 216 return super.visitPostfixExpression(node); |
216 } | 217 } |
217 | 218 |
218 @override | 219 @override |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
601 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { | 602 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { |
602 _errorReporter.reportTypeErrorForNode( | 603 _errorReporter.reportTypeErrorForNode( |
603 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); | 604 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); |
604 return true; | 605 return true; |
605 } | 606 } |
606 } | 607 } |
607 return false; | 608 return false; |
608 } | 609 } |
609 | 610 |
610 /** | 611 /** |
612 * Produces a hint if the given invocation is of a protected method outside | |
613 * a subclass instance method. | |
614 */ | |
615 void _checkForInvalidProtectedMethodCalls(MethodInvocation node) { | |
616 Element element = node.methodName.bestElement; | |
617 if (element == null || !element.isProtected) { | |
618 return; | |
619 } | |
620 | |
621 ClassElement definingClass = element.enclosingElement; | |
622 | |
623 MethodDeclaration decl = | |
624 node.getAncestor((AstNode node) => node is MethodDeclaration); | |
625 if (decl == null) { | |
Brian Wilkerson
2016/02/23 23:42:57
Are we handling static methods as a call site?
cl
pquitslund
2016/02/24 17:12:17
Yep. Test added!
| |
626 _errorReporter.reportErrorForNode( | |
627 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | |
628 node, | |
629 [node.methodName.toString(), definingClass.name]); | |
630 return; | |
631 } | |
632 | |
633 ClassElement invokingClass = decl.element?.enclosingElement; | |
634 if (invokingClass != null) { | |
635 if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) { | |
636 _errorReporter.reportErrorForNode( | |
637 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, | |
638 node, | |
639 [node.methodName.toString(), definingClass.name]); | |
640 } | |
641 } | |
642 } | |
643 | |
644 /** | |
611 * Check that the imported library does not define a loadLibrary function. The import has already | 645 * Check that the imported library does not define a loadLibrary function. The import has already |
612 * been determined to be deferred when this is called. | 646 * been determined to be deferred when this is called. |
613 * | 647 * |
614 * @param node the import directive to evaluate | 648 * @param node the import directive to evaluate |
615 * @param importElement the [ImportElement] retrieved from the node | 649 * @param importElement the [ImportElement] retrieved from the node |
616 * @return `true` if and only if an error code is generated on the passed node | 650 * @return `true` if and only if an error code is generated on the passed node |
617 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. | 651 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. |
618 */ | 652 */ |
619 bool _checkForLoadLibraryFunction( | 653 bool _checkForLoadLibraryFunction( |
620 ImportDirective node, ImportElement importElement) { | 654 ImportDirective node, ImportElement importElement) { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
783 !lhsType.isDynamic && | 817 !lhsType.isDynamic && |
784 !rhsType.isDynamic && | 818 !rhsType.isDynamic && |
785 lhsType.isMoreSpecificThan(rhsType)) { | 819 lhsType.isMoreSpecificThan(rhsType)) { |
786 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); | 820 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); |
787 return true; | 821 return true; |
788 } | 822 } |
789 return false; | 823 return false; |
790 } | 824 } |
791 | 825 |
792 /** | 826 /** |
793 * Check for the passed class declaration for the | |
794 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | |
795 * | |
796 * @param node the class declaration to check | |
797 * @return `true` if and only if a hint code is generated on the passed node | |
798 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. | |
799 */ | |
800 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { | |
801 // ClassElement classElement = node.element; | |
802 // if (classElement == null) { | |
803 // return false; | |
804 // } | |
805 // MethodElement equalsOperatorMethodElement = | |
806 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); | |
807 // if (equalsOperatorMethodElement != null) { | |
808 // PropertyAccessorElement hashCodeElement = | |
809 // classElement.getGetter(_HASHCODE_GETTER_NAME); | |
810 // if (hashCodeElement == null) { | |
811 // _errorReporter.reportErrorForNode( | |
812 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, | |
813 // node.name, | |
814 // [classElement.displayName]); | |
815 // return true; | |
816 // } | |
817 // } | |
818 // return false; | |
819 // } | |
820 | |
821 /** | |
822 * Generate a hint for `noSuchMethod` methods that do nothing except of | 827 * Generate a hint for `noSuchMethod` methods that do nothing except of |
823 * calling another `noSuchMethod` that is not defined by `Object`. | 828 * calling another `noSuchMethod` that is not defined by `Object`. |
824 * | 829 * |
825 * @return `true` if and only if a hint code is generated on the passed node | 830 * @return `true` if and only if a hint code is generated on the passed node |
826 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD]. | 831 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD]. |
827 */ | 832 */ |
828 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) { | 833 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) { |
829 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) { | 834 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) { |
830 return false; | 835 return false; |
831 } | 836 } |
(...skipping 28 matching lines...) Expand all Loading... | |
860 _errorReporter.reportErrorForNode( | 865 _errorReporter.reportErrorForNode( |
861 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); | 866 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); |
862 return true; | 867 return true; |
863 } | 868 } |
864 } | 869 } |
865 } | 870 } |
866 return false; | 871 return false; |
867 } | 872 } |
868 | 873 |
869 /** | 874 /** |
875 * Check for the passed class declaration for the | |
876 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | |
877 * | |
878 * @param node the class declaration to check | |
879 * @return `true` if and only if a hint code is generated on the passed node | |
880 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. | |
881 */ | |
882 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { | |
883 // ClassElement classElement = node.element; | |
884 // if (classElement == null) { | |
885 // return false; | |
886 // } | |
887 // MethodElement equalsOperatorMethodElement = | |
888 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); | |
889 // if (equalsOperatorMethodElement != null) { | |
890 // PropertyAccessorElement hashCodeElement = | |
891 // classElement.getGetter(_HASHCODE_GETTER_NAME); | |
892 // if (hashCodeElement == null) { | |
893 // _errorReporter.reportErrorForNode( | |
894 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, | |
895 // node.name, | |
896 // [classElement.displayName]); | |
897 // return true; | |
898 // } | |
899 // } | |
900 // return false; | |
901 // } | |
902 | |
903 /** | |
870 * Check for situations where the result of a method or function is used, when it returns 'void'. | 904 * Check for situations where the result of a method or function is used, when it returns 'void'. |
871 * | 905 * |
872 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x = | 906 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x = |
873 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return | 907 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return |
874 * m(). | 908 * m(). |
875 * | 909 * |
876 * @param node expression on the RHS of some assignment | 910 * @param node expression on the RHS of some assignment |
877 * @return `true` if and only if a hint code is generated on the passed node | 911 * @return `true` if and only if a hint code is generated on the passed node |
878 * See [HintCode.USE_OF_VOID_RESULT]. | 912 * See [HintCode.USE_OF_VOID_RESULT]. |
879 */ | 913 */ |
880 bool _checkForUseOfVoidResult(Expression expression) { | 914 bool _checkForUseOfVoidResult(Expression expression) { |
881 if (expression == null || expression is! MethodInvocation) { | 915 if (expression == null || expression is! MethodInvocation) { |
882 return false; | 916 return false; |
883 } | 917 } |
884 MethodInvocation methodInvocation = expression as MethodInvocation; | 918 MethodInvocation methodInvocation = expression as MethodInvocation; |
885 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { | 919 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { |
886 SimpleIdentifier methodName = methodInvocation.methodName; | 920 SimpleIdentifier methodName = methodInvocation.methodName; |
887 _errorReporter.reportErrorForNode( | 921 _errorReporter.reportErrorForNode( |
888 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); | 922 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); |
889 return true; | 923 return true; |
890 } | 924 } |
891 return false; | 925 return false; |
892 } | 926 } |
893 | 927 |
928 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) { | |
929 List<ClassElement> seenClasses = <ClassElement>[]; | |
930 while (element != null && !seenClasses.contains(element)) { | |
931 if (element.type == type) { | |
932 return true; | |
933 } | |
934 | |
935 if (element.mixins.any((InterfaceType t) => t == type)) { | |
936 return true; | |
937 } | |
938 | |
939 seenClasses.add(element); | |
940 element = element.supertype?.element; | |
941 } | |
942 | |
943 return false; | |
944 } | |
945 | |
894 /** | 946 /** |
895 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the | 947 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the |
896 * expression that is a parenthesized expression, but whose parent is not a pa renthesized | 948 * expression that is a parenthesized expression, but whose parent is not a pa renthesized |
897 * expression. | 949 * expression. |
898 * | 950 * |
899 * For example given the code `(((e)))`: `(e) -> (((e)))`. | 951 * For example given the code `(((e)))`: `(e) -> (((e)))`. |
900 * | 952 * |
901 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression | 953 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression |
902 * @return the first parent or grand-parent that is a parenthesized expression , that does not have | 954 * @return the first parent or grand-parent that is a parenthesized expression , that does not have |
903 * a parenthesized expression parent | 955 * a parenthesized expression parent |
(...skipping 7476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8380 safelyVisit(node.target); | 8432 safelyVisit(node.target); |
8381 safelyVisit(node.typeArguments); | 8433 safelyVisit(node.typeArguments); |
8382 node.accept(elementResolver); | 8434 node.accept(elementResolver); |
8383 _inferFunctionExpressionsParametersTypes(node.argumentList); | 8435 _inferFunctionExpressionsParametersTypes(node.argumentList); |
8384 _inferArgumentTypesFromContext(node); | 8436 _inferArgumentTypesFromContext(node); |
8385 safelyVisit(node.argumentList); | 8437 safelyVisit(node.argumentList); |
8386 node.accept(typeAnalyzer); | 8438 node.accept(typeAnalyzer); |
8387 return null; | 8439 return null; |
8388 } | 8440 } |
8389 | 8441 |
8390 void _inferArgumentTypesFromContext(InvocationExpression node) { | |
8391 DartType contextType = node.staticInvokeType; | |
8392 if (contextType is FunctionType) { | |
8393 DartType originalType = node.function.staticType; | |
8394 DartType returnContextType = InferenceContext.getType(node); | |
8395 TypeSystem ts = typeSystem; | |
8396 if (returnContextType != null && | |
8397 node.typeArguments == null && | |
8398 originalType is FunctionType && | |
8399 originalType.typeFormals.isNotEmpty && | |
8400 ts is StrongTypeSystemImpl) { | |
8401 | |
8402 contextType = ts.inferGenericFunctionCall(typeProvider, originalType, | |
8403 DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType); | |
8404 } | |
8405 | |
8406 InferenceContext.setType(node.argumentList, contextType); | |
8407 } | |
8408 } | |
8409 | |
8410 @override | 8442 @override |
8411 Object visitNamedExpression(NamedExpression node) { | 8443 Object visitNamedExpression(NamedExpression node) { |
8412 InferenceContext.setType(node.expression, InferenceContext.getType(node)); | 8444 InferenceContext.setType(node.expression, InferenceContext.getType(node)); |
8413 return super.visitNamedExpression(node); | 8445 return super.visitNamedExpression(node); |
8414 } | 8446 } |
8415 | 8447 |
8416 @override | 8448 @override |
8417 Object visitNode(AstNode node) { | 8449 Object visitNode(AstNode node) { |
8418 node.visitChildren(this); | 8450 node.visitChildren(this); |
8419 node.accept(elementResolver); | 8451 node.accept(elementResolver); |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8727 List<ParameterElement> onDataParameters = onDataType.parameters; | 8759 List<ParameterElement> onDataParameters = onDataType.parameters; |
8728 if (onDataParameters == null || onDataParameters.isEmpty) { | 8760 if (onDataParameters == null || onDataParameters.isEmpty) { |
8729 return null; | 8761 return null; |
8730 } | 8762 } |
8731 return onDataParameters[0].type; | 8763 return onDataParameters[0].type; |
8732 } | 8764 } |
8733 } | 8765 } |
8734 return null; | 8766 return null; |
8735 } | 8767 } |
8736 | 8768 |
8769 void _inferArgumentTypesFromContext(InvocationExpression node) { | |
8770 DartType contextType = node.staticInvokeType; | |
8771 if (contextType is FunctionType) { | |
8772 DartType originalType = node.function.staticType; | |
8773 DartType returnContextType = InferenceContext.getType(node); | |
8774 TypeSystem ts = typeSystem; | |
8775 if (returnContextType != null && | |
8776 node.typeArguments == null && | |
8777 originalType is FunctionType && | |
8778 originalType.typeFormals.isNotEmpty && | |
8779 ts is StrongTypeSystemImpl) { | |
8780 contextType = ts.inferGenericFunctionCall(typeProvider, originalType, | |
8781 DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType); | |
8782 } | |
8783 | |
8784 InferenceContext.setType(node.argumentList, contextType); | |
8785 } | |
8786 } | |
8787 | |
8737 void _inferFormalParameterList(FormalParameterList node, DartType type) { | 8788 void _inferFormalParameterList(FormalParameterList node, DartType type) { |
8738 if (typeAnalyzer.inferFormalParameterList(node, type)) { | 8789 if (typeAnalyzer.inferFormalParameterList(node, type)) { |
8739 // TODO(leafp): This gets dropped on the floor if we're in the field | 8790 // TODO(leafp): This gets dropped on the floor if we're in the field |
8740 // inference task. We should probably keep these infos. | 8791 // inference task. We should probably keep these infos. |
8741 inferenceContext.recordInference(node.parent, type); | 8792 inferenceContext.recordInference(node.parent, type); |
8742 } | 8793 } |
8743 } | 8794 } |
8744 | 8795 |
8745 /** | 8796 /** |
8746 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its | 8797 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its |
(...skipping 4053 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12800 nonFields.add(node); | 12851 nonFields.add(node); |
12801 return null; | 12852 return null; |
12802 } | 12853 } |
12803 | 12854 |
12804 @override | 12855 @override |
12805 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 12856 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
12806 | 12857 |
12807 @override | 12858 @override |
12808 Object visitWithClause(WithClause node) => null; | 12859 Object visitWithClause(WithClause node) => null; |
12809 } | 12860 } |
OLD | NEW |