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.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 |