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? | |
Brian Wilkerson
2016/01/08 01:02:21
No.
(1) We use `null` to mean that there is no ty
Jennifer Messerly
2016/01/11 18:49:09
So right now this method is used to populate "stat
Brian Wilkerson
2016/01/11 18:56:41
No. I was distracted by the propagated path. We sh
| |
1342 return null; | |
1343 } | |
1344 | |
1345 DartType invokeType; | |
1346 if (element is PropertyAccessorElement) { | |
1347 invokeType = element.returnType; | |
1348 } else if (element is ExecutableElement) { | |
1349 invokeType = element.type; | |
1350 } else if (element is VariableElement) { | |
1351 invokeType = _promoteManager.getStaticType(element); | |
1352 } | |
1353 | |
1354 return _resolveGenericMethod( | |
1355 invokeType, node.typeArguments, node.methodName); | |
1356 } | |
1357 | |
1331 /** | 1358 /** |
1332 * If the given [element] is a setter, return the getter associated with it. | 1359 * If the given [element] is a setter, return the getter associated with it. |
1333 * Otherwise, return the element unchanged. | 1360 * Otherwise, return the element unchanged. |
1334 */ | 1361 */ |
1335 Element _convertSetterToGetter(Element element) { | 1362 Element _convertSetterToGetter(Element element) { |
1336 // TODO(brianwilkerson) Determine whether and why the element could ever be | 1363 // TODO(brianwilkerson) Determine whether and why the element could ever be |
1337 // a setter. | 1364 // a setter. |
1338 if (element is PropertyAccessorElement) { | 1365 if (element is PropertyAccessorElement) { |
1339 return element.variable.getter; | 1366 return element.variable.getter; |
1340 } | 1367 } |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1457 if (staticType is FunctionType) { | 1484 if (staticType is FunctionType) { |
1458 // | 1485 // |
1459 // All function types are subtypes of 'Function', which is itself a | 1486 // All function types are subtypes of 'Function', which is itself a |
1460 // subclass of 'Object'. | 1487 // subclass of 'Object'. |
1461 // | 1488 // |
1462 staticType = _resolver.typeProvider.functionType; | 1489 staticType = _resolver.typeProvider.functionType; |
1463 } | 1490 } |
1464 return staticType; | 1491 return staticType; |
1465 } | 1492 } |
1466 | 1493 |
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 /** | 1494 /** |
1511 * Return `true` if the given [expression] is a prefix for a deferred import. | 1495 * Return `true` if the given [expression] is a prefix for a deferred import. |
1512 */ | 1496 */ |
1513 bool _isDeferredPrefix(Expression expression) { | 1497 bool _isDeferredPrefix(Expression expression) { |
1514 if (expression is! SimpleIdentifier) { | 1498 if (expression is! SimpleIdentifier) { |
1515 return false; | 1499 return false; |
1516 } | 1500 } |
1517 Element element = (expression as SimpleIdentifier).staticElement; | 1501 Element element = (expression as SimpleIdentifier).staticElement; |
1518 if (element is! PrefixElement) { | 1502 if (element is! PrefixElement) { |
1519 return false; | 1503 return false; |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1744 // Internal error: Unmapped assignment operator. | 1728 // Internal error: Unmapped assignment operator. |
1745 AnalysisEngine.instance.logger.logError( | 1729 AnalysisEngine.instance.logger.logError( |
1746 "Failed to map ${operator.lexeme} to it's corresponding operator"); | 1730 "Failed to map ${operator.lexeme} to it's corresponding operator"); |
1747 return operator; | 1731 return operator; |
1748 } | 1732 } |
1749 break; | 1733 break; |
1750 } | 1734 } |
1751 } | 1735 } |
1752 | 1736 |
1753 /** | 1737 /** |
1738 * Determines if the [propagatedType] of the invoke is better (more specific) | |
1739 * than the [staticType]. If so it will be returned, otherwise returns null. | |
1740 */ | |
1741 DartType _propagatedInvokeTypeIfBetter( | |
Brian Wilkerson
2016/01/08 01:02:21
I think this is now being done in multiple places.
Jennifer Messerly
2016/01/11 18:49:09
Yeah, good idea, we can try and merge this logic w
| |
1742 DartType propagatedType, DartType staticType) { | |
1743 if (propagatedType != null && | |
1744 (staticType == null || propagatedType.isMoreSpecificThan(staticType))) { | |
1745 return propagatedType; | |
1746 } else { | |
1747 return null; | |
1748 } | |
1749 } | |
1750 | |
1751 /** | |
1754 * Record that the given [node] is undefined, causing an error to be reported | 1752 * Record that the given [node] is undefined, causing an error to be reported |
1755 * if appropriate. The [declaringElement] is the element inside which no | 1753 * if appropriate. The [declaringElement] is the element inside which no |
1756 * declaration was found. If this element is a proxy, no error will be | 1754 * 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] | 1755 * 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 | 1756 * is the error code to report. The [arguments] are the arguments to the error |
1759 * message. | 1757 * message. |
1760 */ | 1758 */ |
1761 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, | 1759 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, |
1762 AstNode node, List<Object> arguments) { | 1760 AstNode node, List<Object> arguments) { |
1763 if (_doesntHaveProxy(declaringElement)) { | 1761 if (_doesntHaveProxy(declaringElement)) { |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2067 if (element == null) { | 2065 if (element == null) { |
2068 element = classElement.getMethod(name); | 2066 element = classElement.getMethod(name); |
2069 } | 2067 } |
2070 if (element != null && element.isAccessibleIn(_definingLibrary)) { | 2068 if (element != null && element.isAccessibleIn(_definingLibrary)) { |
2071 return element; | 2069 return element; |
2072 } | 2070 } |
2073 return null; | 2071 return null; |
2074 } | 2072 } |
2075 | 2073 |
2076 /** | 2074 /** |
2075 * Check for a generic method & apply type arguments if any were passed. | |
2076 */ | |
2077 DartType _resolveGenericMethod( | |
Brian Wilkerson
2016/01/08 01:02:21
Ditto
Jennifer Messerly
2016/01/11 18:49:09
Yeah, I was trying to make this method be the shar
Brian Wilkerson
2016/01/11 18:56:41
Agreed. A later CL is fine.
| |
2078 DartType invokeType, TypeArgumentList typeArguments, AstNode node) { | |
2079 // TODO(jmesserly): support generic "call" methods on InterfaceType. | |
2080 if (invokeType is FunctionType) { | |
2081 FunctionType type = invokeType; | |
2082 List<TypeParameterElement> parameters = type.typeFormals; | |
2083 | |
2084 NodeList<TypeName> arguments = typeArguments?.arguments; | |
2085 if (arguments != null && arguments.length != parameters.length) { | |
2086 // Wrong number of type arguments. Ignore them | |
2087 arguments = null; | |
2088 _resolver.reportErrorForNode( | |
2089 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, | |
2090 node, | |
2091 [type, parameters.length, arguments?.length ?? 0]); | |
2092 } | |
2093 if (parameters.isNotEmpty) { | |
2094 if (arguments == null) { | |
2095 invokeType = _resolver.typeSystem.instantiateToBounds(type); | |
2096 } else { | |
2097 invokeType = type.instantiate(arguments.map((n) => n.type).toList()); | |
2098 } | |
2099 } | |
2100 } | |
2101 return invokeType; | |
2102 } | |
2103 | |
2104 /** | |
2077 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the | 2105 * 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 | 2106 * 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 | 2107 * 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 | 2108 * 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 | 2109 * invoked with the arguments. The [methodName] is the name of the method |
2082 * being invoked ('m'). | 2110 * being invoked ('m'). |
2083 */ | 2111 */ |
2084 Element _resolveInvokedElement(SimpleIdentifier methodName) { | 2112 Element _resolveInvokedElement(SimpleIdentifier methodName) { |
2085 // | 2113 // |
2086 // Look first in the lexical scope. | 2114 // Look first in the lexical scope. |
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2570 | 2598 |
2571 @override | 2599 @override |
2572 Element get staticElement => null; | 2600 Element get staticElement => null; |
2573 | 2601 |
2574 @override | 2602 @override |
2575 accept(AstVisitor visitor) => null; | 2603 accept(AstVisitor visitor) => null; |
2576 | 2604 |
2577 @override | 2605 @override |
2578 void visitChildren(AstVisitor visitor) {} | 2606 void visitChildren(AstVisitor visitor) {} |
2579 } | 2607 } |
OLD | NEW |