Chromium Code Reviews| 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 |