| 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.element_resolver; | 5 library analyzer.src.generated.element_resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/element/element.dart'; | 9 import 'package:analyzer/dart/element/element.dart'; |
| 10 import 'package:analyzer/dart/element/type.dart'; | 10 import 'package:analyzer/dart/element/type.dart'; |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 } | 419 } |
| 420 | 420 |
| 421 @override | 421 @override |
| 422 Object visitFunctionDeclaration(FunctionDeclaration node) { | 422 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 423 setMetadata(node.element, node); | 423 setMetadata(node.element, node); |
| 424 return null; | 424 return null; |
| 425 } | 425 } |
| 426 | 426 |
| 427 @override | 427 @override |
| 428 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 428 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 429 // TODO(brianwilkerson) Can we ever resolve the function being invoked? | 429 Expression function = node.function; |
| 430 Expression expression = node.function; | 430 DartType staticInvokeType = |
| 431 if (expression is FunctionExpression) { | 431 _resolveGenericMethod(function.staticType, node.typeArguments, node); |
| 432 FunctionExpression functionExpression = expression; | 432 DartType propagatedInvokeType = _resolveGenericMethod( |
| 433 ExecutableElement functionElement = functionExpression.element; | 433 function.propagatedType, node.typeArguments, node); |
| 434 ArgumentList argumentList = node.argumentList; | 434 |
| 435 List<ParameterElement> parameters = | 435 node.staticInvokeType = staticInvokeType; |
| 436 _resolveArgumentsToFunction(false, argumentList, functionElement); | 436 node.propagatedInvokeType = |
| 437 if (parameters != null) { | 437 _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType); |
| 438 argumentList.correspondingStaticParameters = parameters; | 438 |
| 439 } | 439 List<ParameterElement> parameters = |
| 440 _computeCorrespondingParameters(node.argumentList, staticInvokeType); |
| 441 if (parameters != null) { |
| 442 node.argumentList.correspondingStaticParameters = parameters; |
| 443 } |
| 444 |
| 445 parameters = _computeCorrespondingParameters( |
| 446 node.argumentList, propagatedInvokeType); |
| 447 if (parameters != null) { |
| 448 node.argumentList.correspondingPropagatedParameters = parameters; |
| 440 } | 449 } |
| 441 return null; | 450 return null; |
| 442 } | 451 } |
| 443 | 452 |
| 444 @override | 453 @override |
| 445 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 454 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 446 setMetadata(node.element, node); | 455 setMetadata(node.element, node); |
| 447 return null; | 456 return null; |
| 448 } | 457 } |
| 449 | 458 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 DartType propagatedInvokeType = | 654 DartType propagatedInvokeType = |
| 646 _computeMethodInvokeType(node, propagatedElement); | 655 _computeMethodInvokeType(node, propagatedElement); |
| 647 | 656 |
| 648 // | 657 // |
| 649 // Record the results. | 658 // Record the results. |
| 650 // | 659 // |
| 651 methodName.staticElement = staticElement; | 660 methodName.staticElement = staticElement; |
| 652 methodName.propagatedElement = propagatedElement; | 661 methodName.propagatedElement = propagatedElement; |
| 653 | 662 |
| 654 node.staticInvokeType = staticInvokeType; | 663 node.staticInvokeType = staticInvokeType; |
| 655 if (propagatedInvokeType != null && | 664 // |
| 656 (staticInvokeType == null || | 665 // Store the propagated invoke type if it's more specific than the static |
| 657 propagatedInvokeType.isMoreSpecificThan(staticInvokeType))) { | 666 // type. |
| 658 // Don't store the propagated invoke type unless it's more specific than | 667 // |
| 659 // the static type. We still need to record the propagated parameter | 668 // We still need to record the propagated parameter elements however, |
| 660 // elements however, as that is used for the propagatedType downwards | 669 // as they are used in propagatedType downwards inference of lambda |
| 661 // inference of lambda parameters. | 670 // parameters. So we don't want to clear the propagatedInvokeType variable. |
| 662 node.propagatedInvokeType = propagatedInvokeType; | 671 // |
| 663 } else { | 672 node.propagatedInvokeType = |
| 664 node.propagatedInvokeType = null; | 673 _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType); |
| 665 } | |
| 666 | 674 |
| 667 ArgumentList argumentList = node.argumentList; | 675 ArgumentList argumentList = node.argumentList; |
| 668 if (staticInvokeType != null) { | 676 if (staticInvokeType != null) { |
| 669 List<ParameterElement> parameters = | 677 List<ParameterElement> parameters = |
| 670 _computeCorrespondingParameters(argumentList, staticInvokeType); | 678 _computeCorrespondingParameters(argumentList, staticInvokeType); |
| 671 if (parameters != null) { | 679 if (parameters != null) { |
| 672 argumentList.correspondingStaticParameters = parameters; | 680 argumentList.correspondingStaticParameters = parameters; |
| 673 } | 681 } |
| 674 } | 682 } |
| 675 if (propagatedInvokeType != null) { | 683 if (propagatedInvokeType != null) { |
| (...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1321 if (callMethod != null) { | 1329 if (callMethod != null) { |
| 1322 return _resolveArgumentsToFunction(false, argumentList, callMethod); | 1330 return _resolveArgumentsToFunction(false, argumentList, callMethod); |
| 1323 } | 1331 } |
| 1324 } else if (type is FunctionType) { | 1332 } else if (type is FunctionType) { |
| 1325 return _resolveArgumentsToParameters( | 1333 return _resolveArgumentsToParameters( |
| 1326 false, argumentList, type.parameters); | 1334 false, argumentList, type.parameters); |
| 1327 } | 1335 } |
| 1328 return null; | 1336 return null; |
| 1329 } | 1337 } |
| 1330 | 1338 |
| 1339 DartType _computeMethodInvokeType(MethodInvocation node, Element element) { |
| 1340 if (element == null) { |
| 1341 // TODO(jmesserly): should we return `dynamic` in this case? |
| 1342 // Otherwise we have to guard against `null` every time we use |
| 1343 // `staticInvokeType`. |
| 1344 // If we do return `dynamic` we need to be careful that this doesn't |
| 1345 // adversely affect propagatedType code path. But it shouldn't because |
| 1346 // we'll discard `dynamic` anyway (see _propagatedInvokeTypeIfBetter). |
| 1347 return null; |
| 1348 } |
| 1349 |
| 1350 DartType invokeType; |
| 1351 if (element is PropertyAccessorElement) { |
| 1352 invokeType = element.returnType; |
| 1353 } else if (element is ExecutableElement) { |
| 1354 invokeType = element.type; |
| 1355 } else if (element is VariableElement) { |
| 1356 invokeType = _promoteManager.getStaticType(element); |
| 1357 } |
| 1358 |
| 1359 return _resolveGenericMethod( |
| 1360 invokeType, node.typeArguments, node.methodName); |
| 1361 } |
| 1362 |
| 1331 /** | 1363 /** |
| 1332 * If the given [element] is a setter, return the getter associated with it. | 1364 * If the given [element] is a setter, return the getter associated with it. |
| 1333 * Otherwise, return the element unchanged. | 1365 * Otherwise, return the element unchanged. |
| 1334 */ | 1366 */ |
| 1335 Element _convertSetterToGetter(Element element) { | 1367 Element _convertSetterToGetter(Element element) { |
| 1336 // TODO(brianwilkerson) Determine whether and why the element could ever be | 1368 // TODO(brianwilkerson) Determine whether and why the element could ever be |
| 1337 // a setter. | 1369 // a setter. |
| 1338 if (element is PropertyAccessorElement) { | 1370 if (element is PropertyAccessorElement) { |
| 1339 return element.variable.getter; | 1371 return element.variable.getter; |
| 1340 } | 1372 } |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1457 if (staticType is FunctionType) { | 1489 if (staticType is FunctionType) { |
| 1458 // | 1490 // |
| 1459 // All function types are subtypes of 'Function', which is itself a | 1491 // All function types are subtypes of 'Function', which is itself a |
| 1460 // subclass of 'Object'. | 1492 // subclass of 'Object'. |
| 1461 // | 1493 // |
| 1462 staticType = _resolver.typeProvider.functionType; | 1494 staticType = _resolver.typeProvider.functionType; |
| 1463 } | 1495 } |
| 1464 return staticType; | 1496 return staticType; |
| 1465 } | 1497 } |
| 1466 | 1498 |
| 1467 DartType _computeMethodInvokeType(MethodInvocation node, Element element) { | |
| 1468 if (element == null) { | |
| 1469 return null; | |
| 1470 } | |
| 1471 | |
| 1472 DartType invokeType; | |
| 1473 if (element is PropertyAccessorElement) { | |
| 1474 invokeType = element.returnType; | |
| 1475 } else if (element is ExecutableElement) { | |
| 1476 invokeType = element.type; | |
| 1477 } else if (element is VariableElement) { | |
| 1478 invokeType = _promoteManager.getStaticType(element); | |
| 1479 } | |
| 1480 | |
| 1481 // | |
| 1482 // Check for a generic method & apply type arguments if any were passed. | |
| 1483 // | |
| 1484 // TODO(jmesserly): support generic "call" methods on InterfaceType. | |
| 1485 if (invokeType is FunctionType) { | |
| 1486 FunctionType type = invokeType; | |
| 1487 List<TypeParameterElement> parameters = type.typeFormals; | |
| 1488 | |
| 1489 NodeList<TypeName> arguments = node.typeArguments?.arguments; | |
| 1490 if (arguments != null && arguments.length != parameters.length) { | |
| 1491 // Wrong number of type arguments. Ignore them | |
| 1492 arguments = null; | |
| 1493 _resolver.reportErrorForNode( | |
| 1494 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, | |
| 1495 node.methodName, | |
| 1496 [type, parameters.length, arguments?.length ?? 0]); | |
| 1497 } | |
| 1498 if (parameters.isNotEmpty) { | |
| 1499 if (arguments == null) { | |
| 1500 invokeType = _resolver.typeSystem.instantiateToBounds(type); | |
| 1501 } else { | |
| 1502 invokeType = type.instantiate(arguments.map((n) => n.type).toList()); | |
| 1503 } | |
| 1504 } | |
| 1505 } | |
| 1506 | |
| 1507 return invokeType; | |
| 1508 } | |
| 1509 | |
| 1510 /** | 1499 /** |
| 1511 * Return `true` if the given [expression] is a prefix for a deferred import. | 1500 * Return `true` if the given [expression] is a prefix for a deferred import. |
| 1512 */ | 1501 */ |
| 1513 bool _isDeferredPrefix(Expression expression) { | 1502 bool _isDeferredPrefix(Expression expression) { |
| 1514 if (expression is! SimpleIdentifier) { | 1503 if (expression is! SimpleIdentifier) { |
| 1515 return false; | 1504 return false; |
| 1516 } | 1505 } |
| 1517 Element element = (expression as SimpleIdentifier).staticElement; | 1506 Element element = (expression as SimpleIdentifier).staticElement; |
| 1518 if (element is! PrefixElement) { | 1507 if (element is! PrefixElement) { |
| 1519 return false; | 1508 return false; |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1744 // Internal error: Unmapped assignment operator. | 1733 // Internal error: Unmapped assignment operator. |
| 1745 AnalysisEngine.instance.logger.logError( | 1734 AnalysisEngine.instance.logger.logError( |
| 1746 "Failed to map ${operator.lexeme} to it's corresponding operator"); | 1735 "Failed to map ${operator.lexeme} to it's corresponding operator"); |
| 1747 return operator; | 1736 return operator; |
| 1748 } | 1737 } |
| 1749 break; | 1738 break; |
| 1750 } | 1739 } |
| 1751 } | 1740 } |
| 1752 | 1741 |
| 1753 /** | 1742 /** |
| 1743 * Determines if the [propagatedType] of the invoke is better (more specific) |
| 1744 * than the [staticType]. If so it will be returned, otherwise returns null. |
| 1745 */ |
| 1746 // TODO(jmesserly): can we refactor Resolver.recordPropagatedTypeIfBetter to |
| 1747 // get some code sharing? Right now, this method is to support |
| 1748 // `staticInvokeType` and `propagatedInvokeType`, and the one in Resolver is |
| 1749 // for `staticType` and `propagatedType` on Expression. |
| 1750 DartType _propagatedInvokeTypeIfBetter( |
| 1751 DartType propagatedType, DartType staticType) { |
| 1752 if (propagatedType != null && |
| 1753 (staticType == null || propagatedType.isMoreSpecificThan(staticType))) { |
| 1754 return propagatedType; |
| 1755 } else { |
| 1756 return null; |
| 1757 } |
| 1758 } |
| 1759 |
| 1760 /** |
| 1754 * Record that the given [node] is undefined, causing an error to be reported | 1761 * Record that the given [node] is undefined, causing an error to be reported |
| 1755 * if appropriate. The [declaringElement] is the element inside which no | 1762 * if appropriate. The [declaringElement] is the element inside which no |
| 1756 * declaration was found. If this element is a proxy, no error will be | 1763 * declaration was found. If this element is a proxy, no error will be |
| 1757 * reported. If null, then an error will always be reported. The [errorCode] | 1764 * reported. If null, then an error will always be reported. The [errorCode] |
| 1758 * is the error code to report. The [arguments] are the arguments to the error | 1765 * is the error code to report. The [arguments] are the arguments to the error |
| 1759 * message. | 1766 * message. |
| 1760 */ | 1767 */ |
| 1761 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, | 1768 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, |
| 1762 AstNode node, List<Object> arguments) { | 1769 AstNode node, List<Object> arguments) { |
| 1763 if (_doesntHaveProxy(declaringElement)) { | 1770 if (_doesntHaveProxy(declaringElement)) { |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2067 if (element == null) { | 2074 if (element == null) { |
| 2068 element = classElement.getMethod(name); | 2075 element = classElement.getMethod(name); |
| 2069 } | 2076 } |
| 2070 if (element != null && element.isAccessibleIn(_definingLibrary)) { | 2077 if (element != null && element.isAccessibleIn(_definingLibrary)) { |
| 2071 return element; | 2078 return element; |
| 2072 } | 2079 } |
| 2073 return null; | 2080 return null; |
| 2074 } | 2081 } |
| 2075 | 2082 |
| 2076 /** | 2083 /** |
| 2084 * Check for a generic method & apply type arguments if any were passed. |
| 2085 */ |
| 2086 DartType _resolveGenericMethod( |
| 2087 DartType invokeType, TypeArgumentList typeArguments, AstNode node) { |
| 2088 // TODO(jmesserly): support generic "call" methods on InterfaceType. |
| 2089 if (invokeType is FunctionType) { |
| 2090 FunctionType type = invokeType; |
| 2091 List<TypeParameterElement> parameters = type.typeFormals; |
| 2092 |
| 2093 NodeList<TypeName> arguments = typeArguments?.arguments; |
| 2094 if (arguments != null && arguments.length != parameters.length) { |
| 2095 // Wrong number of type arguments. Ignore them |
| 2096 arguments = null; |
| 2097 _resolver.reportErrorForNode( |
| 2098 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, |
| 2099 node, |
| 2100 [type, parameters.length, arguments?.length ?? 0]); |
| 2101 } |
| 2102 if (parameters.isNotEmpty) { |
| 2103 if (arguments == null) { |
| 2104 invokeType = _resolver.typeSystem.instantiateToBounds(type); |
| 2105 } else { |
| 2106 invokeType = type.instantiate(arguments.map((n) => n.type).toList()); |
| 2107 } |
| 2108 } |
| 2109 } |
| 2110 return invokeType; |
| 2111 } |
| 2112 |
| 2113 /** |
| 2077 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the | 2114 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the |
| 2078 * element being invoked. If the returned element is a method, then the method | 2115 * element being invoked. If the returned element is a method, then the method |
| 2079 * will be invoked. If the returned element is a getter, the getter will be | 2116 * will be invoked. If the returned element is a getter, the getter will be |
| 2080 * invoked without arguments and the result of that invocation will then be | 2117 * invoked without arguments and the result of that invocation will then be |
| 2081 * invoked with the arguments. The [methodName] is the name of the method | 2118 * invoked with the arguments. The [methodName] is the name of the method |
| 2082 * being invoked ('m'). | 2119 * being invoked ('m'). |
| 2083 */ | 2120 */ |
| 2084 Element _resolveInvokedElement(SimpleIdentifier methodName) { | 2121 Element _resolveInvokedElement(SimpleIdentifier methodName) { |
| 2085 // | 2122 // |
| 2086 // Look first in the lexical scope. | 2123 // Look first in the lexical scope. |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2570 | 2607 |
| 2571 @override | 2608 @override |
| 2572 Element get staticElement => null; | 2609 Element get staticElement => null; |
| 2573 | 2610 |
| 2574 @override | 2611 @override |
| 2575 accept(AstVisitor visitor) => null; | 2612 accept(AstVisitor visitor) => null; |
| 2576 | 2613 |
| 2577 @override | 2614 @override |
| 2578 void visitChildren(AstVisitor visitor) {} | 2615 void visitChildren(AstVisitor visitor) {} |
| 2579 } | 2616 } |
| OLD | NEW |