| 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 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 * `null`, avoiding these implicit returns is considered a best practice. | 746 * `null`, avoiding these implicit returns is considered a best practice. |
| 747 * | 747 * |
| 748 * Note: for async functions/methods, this hint only applies when the | 748 * Note: for async functions/methods, this hint only applies when the |
| 749 * function has a return type that Future<Null> is not assignable to. | 749 * function has a return type that Future<Null> is not assignable to. |
| 750 * | 750 * |
| 751 * @param node the binary expression to check | 751 * @param node the binary expression to check |
| 752 * @param body the function body | 752 * @param body the function body |
| 753 * @return `true` if and only if a hint code is generated on the passed node | 753 * @return `true` if and only if a hint code is generated on the passed node |
| 754 * See [HintCode.MISSING_RETURN]. | 754 * See [HintCode.MISSING_RETURN]. |
| 755 */ | 755 */ |
| 756 bool _checkForMissingReturn(TypeName returnType, FunctionBody body) { | 756 void _checkForMissingReturn(TypeName returnType, FunctionBody body) { |
| 757 // Check that the method or function has a return type, and a function body | 757 // Check that the method or function has a return type, and a function body |
| 758 if (returnType == null || body == null) { | 758 if (returnType == null || body == null) { |
| 759 return false; | 759 return; |
| 760 } | 760 } |
| 761 // Check that the body is a BlockFunctionBody | 761 // Check that the body is a BlockFunctionBody |
| 762 if (body is! BlockFunctionBody) { | 762 if (body is BlockFunctionBody) { |
| 763 return false; | 763 // Generators are never required to have a return statement. |
| 764 if (body.isGenerator) { |
| 765 return; |
| 766 } |
| 767 // Check that the type is resolvable, and is not "void" |
| 768 DartType returnTypeType = returnType.type; |
| 769 if (returnTypeType == null || returnTypeType.isVoid) { |
| 770 return; |
| 771 } |
| 772 // For async, give no hint if Future<Null> is assignable to the return |
| 773 // type. |
| 774 if (body.isAsynchronous && |
| 775 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) { |
| 776 return; |
| 777 } |
| 778 // Check the block for a return statement, if not, create the hint |
| 779 if (!ExitDetector.exits(body)) { |
| 780 _errorReporter.reportErrorForNode( |
| 781 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]); |
| 782 } |
| 764 } | 783 } |
| 765 // Generators are never required to have a return statement. | |
| 766 if (body.isGenerator) { | |
| 767 return false; | |
| 768 } | |
| 769 // Check that the type is resolvable, and is not "void" | |
| 770 DartType returnTypeType = returnType.type; | |
| 771 if (returnTypeType == null || returnTypeType.isVoid) { | |
| 772 return false; | |
| 773 } | |
| 774 // For async, give no hint if Future<Null> is assignable to the return | |
| 775 // type. | |
| 776 if (body.isAsynchronous && | |
| 777 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) { | |
| 778 return false; | |
| 779 } | |
| 780 // Check the block for a return statement, if not, create the hint | |
| 781 BlockFunctionBody blockFunctionBody = body as BlockFunctionBody; | |
| 782 if (!ExitDetector.exits(blockFunctionBody)) { | |
| 783 _errorReporter.reportErrorForNode( | |
| 784 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]); | |
| 785 return true; | |
| 786 } | |
| 787 return false; | |
| 788 } | 784 } |
| 789 | 785 |
| 790 /** | 786 /** |
| 791 * Produce a hint if the given [condition] could have a value of `null`. | 787 * Produce a hint if the given [condition] could have a value of `null`. |
| 792 */ | 788 */ |
| 793 void _checkForPossibleNullCondition(Expression condition) { | 789 void _checkForPossibleNullCondition(Expression condition) { |
| 794 while (condition is ParenthesizedExpression) { | 790 while (condition is ParenthesizedExpression) { |
| 795 condition = (condition as ParenthesizedExpression).expression; | 791 condition = (condition as ParenthesizedExpression).expression; |
| 796 } | 792 } |
| 797 if (condition is BinaryExpression) { | 793 if (condition is BinaryExpression) { |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, | 964 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, |
| 969 // node.name, | 965 // node.name, |
| 970 // [classElement.displayName]); | 966 // [classElement.displayName]); |
| 971 // return true; | 967 // return true; |
| 972 // } | 968 // } |
| 973 // } | 969 // } |
| 974 // return false; | 970 // return false; |
| 975 // } | 971 // } |
| 976 | 972 |
| 977 /** | 973 /** |
| 978 * Check for situations where the result of a method or function is used, when
it returns 'void'. | 974 * Check for situations where the result of a method or function is used, when |
| 975 * it returns 'void'. |
| 979 * | 976 * |
| 980 * TODO(jwren) Many other situations of use could be covered. We currently cov
er the cases var x = | |
| 981 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m
(), f(m()), return | |
| 982 * m(). | |
| 983 * | |
| 984 * @param node expression on the RHS of some assignment | |
| 985 * @return `true` if and only if a hint code is generated on the passed node | |
| 986 * See [HintCode.USE_OF_VOID_RESULT]. | 977 * See [HintCode.USE_OF_VOID_RESULT]. |
| 987 */ | 978 */ |
| 988 bool _checkForUseOfVoidResult(Expression expression) { | 979 void _checkForUseOfVoidResult(Expression expression) { |
| 989 if (expression == null || expression is! MethodInvocation) { | 980 // TODO(jwren) Many other situations of use could be covered. We currently |
| 990 return false; | 981 // cover the cases var x = m() and x = m(), but we could also cover cases |
| 982 // such as m().x, m()[k], a + m(), f(m()), return m(). |
| 983 if (expression is MethodInvocation) { |
| 984 if (identical(expression.staticType, VoidTypeImpl.instance)) { |
| 985 SimpleIdentifier methodName = expression.methodName; |
| 986 _errorReporter.reportErrorForNode( |
| 987 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); |
| 988 } |
| 991 } | 989 } |
| 992 MethodInvocation methodInvocation = expression as MethodInvocation; | |
| 993 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { | |
| 994 SimpleIdentifier methodName = methodInvocation.methodName; | |
| 995 _errorReporter.reportErrorForNode( | |
| 996 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); | |
| 997 return true; | |
| 998 } | |
| 999 return false; | |
| 1000 } | 990 } |
| 1001 | 991 |
| 1002 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) { | 992 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) { |
| 1003 List<ClassElement> seenClasses = <ClassElement>[]; | 993 List<ClassElement> seenClasses = <ClassElement>[]; |
| 1004 while (element != null && !seenClasses.contains(element)) { | 994 while (element != null && !seenClasses.contains(element)) { |
| 1005 if (element.type == type) { | 995 if (element.type == type) { |
| 1006 return true; | 996 return true; |
| 1007 } | 997 } |
| 1008 | 998 |
| 1009 if (element.mixins.any((InterfaceType t) => t == type)) { | 999 if (element.mixins.any((InterfaceType t) => t == type)) { |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1414 */ | 1404 */ |
| 1415 bool _implementsEqualsWhenNotAllowed(DartType type) { | 1405 bool _implementsEqualsWhenNotAllowed(DartType type) { |
| 1416 // ignore int or String | 1406 // ignore int or String |
| 1417 if (type == null || type == _intType || type == _typeProvider.stringType) { | 1407 if (type == null || type == _intType || type == _typeProvider.stringType) { |
| 1418 return false; | 1408 return false; |
| 1419 } else if (type == _typeProvider.doubleType) { | 1409 } else if (type == _typeProvider.doubleType) { |
| 1420 return true; | 1410 return true; |
| 1421 } | 1411 } |
| 1422 // prepare ClassElement | 1412 // prepare ClassElement |
| 1423 Element element = type.element; | 1413 Element element = type.element; |
| 1424 if (element is! ClassElement) { | 1414 if (element is ClassElement) { |
| 1425 return false; | 1415 // lookup for == |
| 1416 MethodElement method = |
| 1417 element.lookUpConcreteMethod("==", _currentLibrary); |
| 1418 if (method == null || method.enclosingElement.type.isObject) { |
| 1419 return false; |
| 1420 } |
| 1421 // there is == that we don't like |
| 1422 return true; |
| 1426 } | 1423 } |
| 1427 ClassElement classElement = element as ClassElement; | 1424 return false; |
| 1428 // lookup for == | |
| 1429 MethodElement method = | |
| 1430 classElement.lookUpConcreteMethod("==", _currentLibrary); | |
| 1431 if (method == null || method.enclosingElement.type.isObject) { | |
| 1432 return false; | |
| 1433 } | |
| 1434 // there is == that we don't like | |
| 1435 return true; | |
| 1436 } | 1425 } |
| 1437 | 1426 |
| 1438 /** | 1427 /** |
| 1439 * Given some computed [Expression], this method generates the passed [ErrorCo
de] on | 1428 * Given some computed [Expression], this method generates the passed [ErrorCo
de] on |
| 1440 * the node if its' value consists of information from a deferred library. | 1429 * the node if its' value consists of information from a deferred library. |
| 1441 * | 1430 * |
| 1442 * @param expression the expression to be tested for a deferred library refere
nce | 1431 * @param expression the expression to be tested for a deferred library refere
nce |
| 1443 * @param errorCode the error code to be used if the expression is or consists
of a reference to a | 1432 * @param errorCode the error code to be used if the expression is or consists
of a reference to a |
| 1444 * deferred library | 1433 * deferred library |
| 1445 */ | 1434 */ |
| (...skipping 4166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5612 * Return the static element associated with the given expression whose type c
an be promoted, or | 5601 * Return the static element associated with the given expression whose type c
an be promoted, or |
| 5613 * `null` if there is no element whose type can be promoted. | 5602 * `null` if there is no element whose type can be promoted. |
| 5614 * | 5603 * |
| 5615 * @param expression the expression with which the element is associated | 5604 * @param expression the expression with which the element is associated |
| 5616 * @return the element associated with the given expression | 5605 * @return the element associated with the given expression |
| 5617 */ | 5606 */ |
| 5618 VariableElement getPromotionStaticElement(Expression expression) { | 5607 VariableElement getPromotionStaticElement(Expression expression) { |
| 5619 while (expression is ParenthesizedExpression) { | 5608 while (expression is ParenthesizedExpression) { |
| 5620 expression = (expression as ParenthesizedExpression).expression; | 5609 expression = (expression as ParenthesizedExpression).expression; |
| 5621 } | 5610 } |
| 5622 if (expression is! SimpleIdentifier) { | 5611 if (expression is SimpleIdentifier) { |
| 5623 return null; | 5612 Element element = expression.staticElement; |
| 5624 } | 5613 if (element is VariableElement) { |
| 5625 SimpleIdentifier identifier = expression as SimpleIdentifier; | 5614 ElementKind kind = element.kind; |
| 5626 Element element = identifier.staticElement; | 5615 if (kind == ElementKind.LOCAL_VARIABLE || |
| 5627 if (element is! VariableElement) { | 5616 kind == ElementKind.PARAMETER) { |
| 5628 return null; | 5617 return element; |
| 5629 } | 5618 } |
| 5630 ElementKind kind = element.kind; | 5619 } |
| 5631 if (kind == ElementKind.LOCAL_VARIABLE) { | |
| 5632 return element as VariableElement; | |
| 5633 } | |
| 5634 if (kind == ElementKind.PARAMETER) { | |
| 5635 return element as VariableElement; | |
| 5636 } | 5620 } |
| 5637 return null; | 5621 return null; |
| 5638 } | 5622 } |
| 5639 | 5623 |
| 5640 /** | 5624 /** |
| 5641 * Prepares this [ResolverVisitor] to using it for incremental resolution. | 5625 * Prepares this [ResolverVisitor] to using it for incremental resolution. |
| 5642 */ | 5626 */ |
| 5643 void initForIncrementalResolution() { | 5627 void initForIncrementalResolution() { |
| 5644 _overrideManager.enterScope(); | 5628 _overrideManager.enterScope(); |
| 5645 } | 5629 } |
| (...skipping 3961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9607 if (typeName is PrefixedIdentifier && | 9591 if (typeName is PrefixedIdentifier && |
| 9608 parent is ConstructorName && | 9592 parent is ConstructorName && |
| 9609 argumentList == null) { | 9593 argumentList == null) { |
| 9610 ConstructorName name = parent; | 9594 ConstructorName name = parent; |
| 9611 if (name.name == null) { | 9595 if (name.name == null) { |
| 9612 PrefixedIdentifier prefixedIdentifier = | 9596 PrefixedIdentifier prefixedIdentifier = |
| 9613 typeName as PrefixedIdentifier; | 9597 typeName as PrefixedIdentifier; |
| 9614 SimpleIdentifier prefix = prefixedIdentifier.prefix; | 9598 SimpleIdentifier prefix = prefixedIdentifier.prefix; |
| 9615 element = nameScope.lookup(prefix, definingLibrary); | 9599 element = nameScope.lookup(prefix, definingLibrary); |
| 9616 if (element is PrefixElement) { | 9600 if (element is PrefixElement) { |
| 9617 if (parent.parent is InstanceCreationExpression && | 9601 AstNode grandParent = parent.parent; |
| 9618 (parent.parent as InstanceCreationExpression).isConst) { | 9602 if (grandParent is InstanceCreationExpression && |
| 9603 grandParent.isConst) { |
| 9619 // If, if this is a const expression, then generate a | 9604 // If, if this is a const expression, then generate a |
| 9620 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error. | 9605 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error. |
| 9621 reportErrorForNode( | 9606 reportErrorForNode( |
| 9622 CompileTimeErrorCode.CONST_WITH_NON_TYPE, | 9607 CompileTimeErrorCode.CONST_WITH_NON_TYPE, |
| 9623 prefixedIdentifier.identifier, | 9608 prefixedIdentifier.identifier, |
| 9624 [prefixedIdentifier.identifier.name]); | 9609 [prefixedIdentifier.identifier.name]); |
| 9625 } else { | 9610 } else { |
| 9626 // Else, if this expression is a new expression, report a | 9611 // Else, if this expression is a new expression, report a |
| 9627 // NEW_WITH_NON_TYPE warning. | 9612 // NEW_WITH_NON_TYPE warning. |
| 9628 reportErrorForNode( | 9613 reportErrorForNode( |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9889 ClassElementImpl _getClassElement(SimpleIdentifier identifier) { | 9874 ClassElementImpl _getClassElement(SimpleIdentifier identifier) { |
| 9890 // TODO(brianwilkerson) Seems like we should be using | 9875 // TODO(brianwilkerson) Seems like we should be using |
| 9891 // ClassDeclaration.getElement(). | 9876 // ClassDeclaration.getElement(). |
| 9892 if (identifier == null) { | 9877 if (identifier == null) { |
| 9893 // TODO(brianwilkerson) Report this | 9878 // TODO(brianwilkerson) Report this |
| 9894 // Internal error: We should never build a class declaration without a | 9879 // Internal error: We should never build a class declaration without a |
| 9895 // name. | 9880 // name. |
| 9896 return null; | 9881 return null; |
| 9897 } | 9882 } |
| 9898 Element element = identifier.staticElement; | 9883 Element element = identifier.staticElement; |
| 9899 if (element is! ClassElementImpl) { | 9884 if (element is ClassElementImpl) { |
| 9900 // TODO(brianwilkerson) Report this | 9885 return element; |
| 9901 // Internal error: Failed to create an element for a class declaration. | |
| 9902 return null; | |
| 9903 } | 9886 } |
| 9904 return element as ClassElementImpl; | 9887 // TODO(brianwilkerson) Report this |
| 9888 // Internal error: Failed to create an element for a class declaration. |
| 9889 return null; |
| 9905 } | 9890 } |
| 9906 | 9891 |
| 9907 /** | 9892 /** |
| 9908 * Return an array containing all of the elements associated with the paramete
rs in the given | 9893 * Return an array containing all of the elements associated with the paramete
rs in the given |
| 9909 * list. | 9894 * list. |
| 9910 * | 9895 * |
| 9911 * @param parameterList the list of parameters whose elements are to be return
ed | 9896 * @param parameterList the list of parameters whose elements are to be return
ed |
| 9912 * @return the elements associated with the parameters | 9897 * @return the elements associated with the parameters |
| 9913 */ | 9898 */ |
| 9914 List<ParameterElement> _getElements(FormalParameterList parameterList) { | 9899 List<ParameterElement> _getElements(FormalParameterList parameterList) { |
| (...skipping 911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10826 return null; | 10811 return null; |
| 10827 } | 10812 } |
| 10828 if (identical(node.staticElement, variable)) { | 10813 if (identical(node.staticElement, variable)) { |
| 10829 if (node.inSetterContext()) { | 10814 if (node.inSetterContext()) { |
| 10830 result = true; | 10815 result = true; |
| 10831 } | 10816 } |
| 10832 } | 10817 } |
| 10833 return null; | 10818 return null; |
| 10834 } | 10819 } |
| 10835 } | 10820 } |
| OLD | NEW |