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 |