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'; |
11 import 'package:analyzer/src/dart/element/element.dart'; | 11 import 'package:analyzer/src/dart/element/element.dart'; |
12 import 'package:analyzer/src/dart/element/member.dart'; | |
13 import 'package:analyzer/src/dart/element/type.dart'; | 12 import 'package:analyzer/src/dart/element/type.dart'; |
14 import 'package:analyzer/src/generated/ast.dart'; | 13 import 'package:analyzer/src/generated/ast.dart'; |
15 import 'package:analyzer/src/generated/engine.dart'; | 14 import 'package:analyzer/src/generated/engine.dart'; |
16 import 'package:analyzer/src/generated/error.dart'; | 15 import 'package:analyzer/src/generated/error.dart'; |
17 import 'package:analyzer/src/generated/resolver.dart'; | 16 import 'package:analyzer/src/generated/resolver.dart'; |
18 import 'package:analyzer/src/generated/scanner.dart' as sc; | 17 import 'package:analyzer/src/generated/scanner.dart' as sc; |
19 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
20 | 18 |
21 /** | 19 /** |
22 * An object used by instances of [ResolverVisitor] to resolve references within | 20 * An object used by instances of [ResolverVisitor] to resolve references within |
23 * the AST structure to the elements being referenced. The requirements for the | 21 * the AST structure to the elements being referenced. The requirements for the |
24 * element resolver are: | 22 * element resolver are: |
25 * | 23 * |
26 * 1. Every [SimpleIdentifier] should be resolved to the element to which it | 24 * 1. Every [SimpleIdentifier] should be resolved to the element to which it |
27 * refers. Specifically: | 25 * refers. Specifically: |
28 * * An identifier within the declaration of that name should resolve to the | 26 * * An identifier within the declaration of that name should resolve to the |
29 * element being declared. | 27 * element being declared. |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
632 target, staticType, methodName, isConditional); | 630 target, staticType, methodName, isConditional); |
633 // If we have propagated type information use it (since it should | 631 // If we have propagated type information use it (since it should |
634 // not be redundant with the staticType). Otherwise, don't produce | 632 // not be redundant with the staticType). Otherwise, don't produce |
635 // a propagatedElement which duplicates the staticElement. | 633 // a propagatedElement which duplicates the staticElement. |
636 if (propagatedType is InterfaceType) { | 634 if (propagatedType is InterfaceType) { |
637 propagatedElement = _resolveInvokedElementWithTarget( | 635 propagatedElement = _resolveInvokedElementWithTarget( |
638 target, propagatedType, methodName, isConditional); | 636 target, propagatedType, methodName, isConditional); |
639 } | 637 } |
640 } | 638 } |
641 } | 639 } |
642 // | |
643 // Check for a generic method & apply type arguments if any were passed. | |
644 // | |
645 if (staticElement is MethodElement || staticElement is FunctionElement) { | |
646 FunctionType type = (staticElement as ExecutableElement).type; | |
647 List<TypeParameterElement> parameters = type.boundTypeParameters; | |
648 | |
649 NodeList<TypeName> arguments = node.typeArguments?.arguments; | |
650 if (arguments != null && arguments.length != parameters.length) { | |
651 // Wrong number of type arguments. Ignore them | |
652 arguments = null; | |
653 _resolver.reportErrorForNode( | |
654 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, | |
655 methodName, | |
656 [type, parameters.length, arguments.length]); | |
657 } | |
658 if (parameters.isNotEmpty) { | |
659 List<DartType> typeArgs; | |
660 if (arguments == null) { | |
661 typeArgs = new List<DartType>.filled( | |
662 parameters.length, DynamicTypeImpl.instance); | |
663 } else { | |
664 typeArgs = new List<DartType>.from(arguments.map((n) => n.type)); | |
665 } | |
666 type = type.instantiate(typeArgs); | |
667 | |
668 if (staticElement is MethodMember) { | |
669 MethodMember member = staticElement; | |
670 staticElement = | |
671 new MethodMember(member.baseElement, member.definingType, type); | |
672 } else if (staticElement is MethodElement) { | |
673 ClassElement clazz = staticElement.enclosingElement; | |
674 staticElement = new MethodMember(staticElement, clazz.type, type); | |
675 } else { | |
676 staticElement = | |
677 new FunctionMember(staticElement as FunctionElement, type); | |
678 } | |
679 } | |
680 } | |
681 | 640 |
682 staticElement = _convertSetterToGetter(staticElement); | 641 staticElement = _convertSetterToGetter(staticElement); |
683 propagatedElement = _convertSetterToGetter(propagatedElement); | 642 propagatedElement = _convertSetterToGetter(propagatedElement); |
643 | |
644 DartType staticInvokeType = _computeMethodInvokeType(node, staticElement); | |
645 DartType propagatedInvokeType = | |
Brian Wilkerson
2016/01/06 21:57:34
If the propagatedInvokeType is not `null` and is n
Jennifer Messerly
2016/01/06 22:25:51
Yeah that's a good point. I think we get this for
Brian Wilkerson
2016/01/06 22:47:01
Unfortunately, no. It's perfectly valid for both t
Jennifer Messerly
2016/01/06 22:52:48
Ah that makes sense. Does something like this look
Brian Wilkerson
2016/01/07 00:24:22
See ResolverVisitor.recordPropagatedTypeIfBetter.
Jennifer Messerly
2016/01/07 00:33:29
Ah, nice! Looking through there, I think the logic
| |
646 _computeMethodInvokeType(node, propagatedElement); | |
647 | |
684 // | 648 // |
685 // Record the results. | 649 // Record the results. |
686 // | 650 // |
687 methodName.staticElement = staticElement; | 651 methodName.staticElement = staticElement; |
688 methodName.propagatedElement = propagatedElement; | 652 methodName.propagatedElement = propagatedElement; |
653 | |
654 node.staticInvokeType = staticInvokeType; | |
655 node.propagatedInvokeType = propagatedInvokeType; | |
656 | |
689 ArgumentList argumentList = node.argumentList; | 657 ArgumentList argumentList = node.argumentList; |
690 if (staticElement != null) { | 658 if (staticInvokeType != null) { |
691 List<ParameterElement> parameters = | 659 List<ParameterElement> parameters = |
692 _computeCorrespondingParameters(argumentList, staticElement); | 660 _computeCorrespondingParameters(argumentList, staticInvokeType); |
693 if (parameters != null) { | 661 if (parameters != null) { |
694 argumentList.correspondingStaticParameters = parameters; | 662 argumentList.correspondingStaticParameters = parameters; |
695 } | 663 } |
696 } | 664 } |
697 if (propagatedElement != null) { | 665 if (propagatedInvokeType != null) { |
698 List<ParameterElement> parameters = | 666 List<ParameterElement> parameters = |
699 _computeCorrespondingParameters(argumentList, propagatedElement); | 667 _computeCorrespondingParameters(argumentList, propagatedInvokeType); |
700 if (parameters != null) { | 668 if (parameters != null) { |
701 argumentList.correspondingPropagatedParameters = parameters; | 669 argumentList.correspondingPropagatedParameters = parameters; |
702 } | 670 } |
703 } | 671 } |
704 // | 672 // |
705 // Then check for error conditions. | 673 // Then check for error conditions. |
706 // | 674 // |
707 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); | 675 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); |
708 bool generatedWithTypePropagation = false; | 676 bool generatedWithTypePropagation = false; |
709 if (_enableHints && errorCode == null && staticElement == null) { | 677 if (_enableHints && errorCode == null && staticElement == null) { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1329 return false; | 1297 return false; |
1330 } | 1298 } |
1331 | 1299 |
1332 /** | 1300 /** |
1333 * Given an [argumentList] and the executable [element] that will be invoked | 1301 * Given an [argumentList] and the executable [element] that will be invoked |
1334 * using those arguments, compute the list of parameters that correspond to | 1302 * using those arguments, compute the list of parameters that correspond to |
1335 * the list of arguments. Return the parameters that correspond to the | 1303 * the list of arguments. Return the parameters that correspond to the |
1336 * arguments, or `null` if no correspondence could be computed. | 1304 * arguments, or `null` if no correspondence could be computed. |
1337 */ | 1305 */ |
1338 List<ParameterElement> _computeCorrespondingParameters( | 1306 List<ParameterElement> _computeCorrespondingParameters( |
1339 ArgumentList argumentList, Element element) { | 1307 ArgumentList argumentList, DartType type) { |
1340 if (element is PropertyAccessorElement) { | 1308 if (type is InterfaceType) { |
1341 // | 1309 MethodElement callMethod = |
1342 // This is an invocation of the call method defined on the value returned | 1310 type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary); |
1343 // by the getter. | 1311 if (callMethod != null) { |
1344 // | 1312 return _resolveArgumentsToFunction(false, argumentList, callMethod); |
1345 FunctionType getterType = element.type; | |
1346 if (getterType != null) { | |
1347 DartType getterReturnType = getterType.returnType; | |
1348 if (getterReturnType is InterfaceType) { | |
1349 MethodElement callMethod = getterReturnType.lookUpMethod( | |
1350 FunctionElement.CALL_METHOD_NAME, _definingLibrary); | |
1351 if (callMethod != null) { | |
1352 return _resolveArgumentsToFunction(false, argumentList, callMethod); | |
1353 } | |
1354 } else if (getterReturnType is FunctionType) { | |
1355 List<ParameterElement> parameters = getterReturnType.parameters; | |
1356 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
1357 } | |
1358 } | 1313 } |
1359 } else if (element is ExecutableElement) { | 1314 } else if (type is FunctionType) { |
1360 return _resolveArgumentsToFunction(false, argumentList, element); | 1315 return _resolveArgumentsToParameters( |
1361 } else if (element is VariableElement) { | 1316 false, argumentList, type.parameters); |
1362 VariableElement variable = element; | |
1363 DartType type = _promoteManager.getStaticType(variable); | |
1364 if (type is FunctionType) { | |
1365 FunctionType functionType = type; | |
1366 List<ParameterElement> parameters = functionType.parameters; | |
1367 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
1368 } else if (type is InterfaceType) { | |
1369 // "call" invocation | |
1370 MethodElement callMethod = type.lookUpMethod( | |
1371 FunctionElement.CALL_METHOD_NAME, _definingLibrary); | |
1372 if (callMethod != null) { | |
1373 List<ParameterElement> parameters = callMethod.parameters; | |
1374 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
1375 } | |
1376 } | |
1377 } | 1317 } |
1378 return null; | 1318 return null; |
1379 } | 1319 } |
1380 | 1320 |
1381 /** | 1321 /** |
1382 * If the given [element] is a setter, return the getter associated with it. | 1322 * If the given [element] is a setter, return the getter associated with it. |
1383 * Otherwise, return the element unchanged. | 1323 * Otherwise, return the element unchanged. |
1384 */ | 1324 */ |
1385 Element _convertSetterToGetter(Element element) { | 1325 Element _convertSetterToGetter(Element element) { |
1386 // TODO(brianwilkerson) Determine whether and why the element could ever be | 1326 // TODO(brianwilkerson) Determine whether and why the element could ever be |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1507 if (staticType is FunctionType) { | 1447 if (staticType is FunctionType) { |
1508 // | 1448 // |
1509 // All function types are subtypes of 'Function', which is itself a | 1449 // All function types are subtypes of 'Function', which is itself a |
1510 // subclass of 'Object'. | 1450 // subclass of 'Object'. |
1511 // | 1451 // |
1512 staticType = _resolver.typeProvider.functionType; | 1452 staticType = _resolver.typeProvider.functionType; |
1513 } | 1453 } |
1514 return staticType; | 1454 return staticType; |
1515 } | 1455 } |
1516 | 1456 |
1457 DartType _computeMethodInvokeType(MethodInvocation node, Element element) { | |
1458 if (element == null) { | |
1459 return null; | |
1460 } | |
1461 | |
1462 DartType invokeType; | |
1463 if (element is PropertyAccessorElement) { | |
1464 invokeType = element.returnType; | |
1465 } else if (element is ExecutableElement) { | |
1466 invokeType = element.type; | |
1467 } else if (element is VariableElement) { | |
1468 invokeType = _promoteManager.getStaticType(element); | |
1469 } | |
1470 | |
1471 // | |
1472 // Check for a generic method & apply type arguments if any were passed. | |
1473 // | |
1474 // TODO(jmesserly): should we support for generic "call" methods on | |
Brian Wilkerson
2016/01/06 21:57:34
"should we support for"?
Jennifer Messerly
2016/01/06 22:25:51
DOH. Good catch! It got stuck halfway between an e
| |
1475 // InterfaceType? | |
1476 if (invokeType is FunctionType) { | |
1477 FunctionType type = invokeType; | |
1478 List<TypeParameterElement> parameters = type.typeFormals; | |
1479 | |
1480 NodeList<TypeName> arguments = node.typeArguments?.arguments; | |
1481 if (arguments != null && arguments.length != parameters.length) { | |
1482 // Wrong number of type arguments. Ignore them | |
1483 arguments = null; | |
1484 _resolver.reportErrorForNode( | |
1485 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, | |
1486 node.methodName, | |
1487 [type, parameters.length, arguments.length]); | |
1488 } | |
1489 if (parameters.isNotEmpty) { | |
1490 if (arguments == null) { | |
1491 invokeType = _resolver.typeSystem.instantiateToBounds(type); | |
1492 } else { | |
1493 invokeType = type.instantiate(arguments.map((n) => n.type).toList()); | |
1494 } | |
1495 } | |
1496 } | |
1497 | |
1498 return invokeType; | |
1499 } | |
1500 | |
1517 /** | 1501 /** |
1518 * Return `true` if the given [expression] is a prefix for a deferred import. | 1502 * Return `true` if the given [expression] is a prefix for a deferred import. |
1519 */ | 1503 */ |
1520 bool _isDeferredPrefix(Expression expression) { | 1504 bool _isDeferredPrefix(Expression expression) { |
1521 if (expression is! SimpleIdentifier) { | 1505 if (expression is! SimpleIdentifier) { |
1522 return false; | 1506 return false; |
1523 } | 1507 } |
1524 Element element = (expression as SimpleIdentifier).staticElement; | 1508 Element element = (expression as SimpleIdentifier).staticElement; |
1525 if (element is! PrefixElement) { | 1509 if (element is! PrefixElement) { |
1526 return false; | 1510 return false; |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1966 * Given an [argumentList] and the [parameters] related to the element that | 1950 * Given an [argumentList] and the [parameters] related to the element that |
1967 * will be invoked using those arguments, compute the list of parameters that | 1951 * will be invoked using those arguments, compute the list of parameters that |
1968 * correspond to the list of arguments. An error will be reported if any of | 1952 * correspond to the list of arguments. An error will be reported if any of |
1969 * the arguments cannot be matched to a parameter. The flag [reportError] | 1953 * the arguments cannot be matched to a parameter. The flag [reportError] |
1970 * should be `true` if a compile-time error should be reported; or `false` if | 1954 * should be `true` if a compile-time error should be reported; or `false` if |
1971 * a compile-time warning should be reported. Return the parameters that | 1955 * a compile-time warning should be reported. Return the parameters that |
1972 * correspond to the arguments. | 1956 * correspond to the arguments. |
1973 */ | 1957 */ |
1974 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, | 1958 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, |
1975 ArgumentList argumentList, List<ParameterElement> parameters) { | 1959 ArgumentList argumentList, List<ParameterElement> parameters) { |
1976 List<ParameterElement> requiredParameters = new List<ParameterElement>(); | 1960 return ResolverVisitor.resolveArgumentsToParameters( |
1977 List<ParameterElement> positionalParameters = new List<ParameterElement>(); | 1961 argumentList, parameters, _resolver.reportErrorForNode, |
1978 HashMap<String, ParameterElement> namedParameters = | 1962 reportError: reportError); |
1979 new HashMap<String, ParameterElement>(); | |
1980 for (ParameterElement parameter in parameters) { | |
1981 ParameterKind kind = parameter.parameterKind; | |
1982 if (kind == ParameterKind.REQUIRED) { | |
1983 requiredParameters.add(parameter); | |
1984 } else if (kind == ParameterKind.POSITIONAL) { | |
1985 positionalParameters.add(parameter); | |
1986 } else { | |
1987 namedParameters[parameter.name] = parameter; | |
1988 } | |
1989 } | |
1990 List<ParameterElement> unnamedParameters = | |
1991 new List<ParameterElement>.from(requiredParameters); | |
1992 unnamedParameters.addAll(positionalParameters); | |
1993 int unnamedParameterCount = unnamedParameters.length; | |
1994 int unnamedIndex = 0; | |
1995 NodeList<Expression> arguments = argumentList.arguments; | |
1996 int argumentCount = arguments.length; | |
1997 List<ParameterElement> resolvedParameters = | |
1998 new List<ParameterElement>(argumentCount); | |
1999 int positionalArgumentCount = 0; | |
2000 HashSet<String> usedNames = new HashSet<String>(); | |
2001 bool noBlankArguments = true; | |
2002 for (int i = 0; i < argumentCount; i++) { | |
2003 Expression argument = arguments[i]; | |
2004 if (argument is NamedExpression) { | |
2005 SimpleIdentifier nameNode = argument.name.label; | |
2006 String name = nameNode.name; | |
2007 ParameterElement element = namedParameters[name]; | |
2008 if (element == null) { | |
2009 ErrorCode errorCode = (reportError | |
2010 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER | |
2011 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER); | |
2012 _resolver.reportErrorForNode(errorCode, nameNode, [name]); | |
2013 } else { | |
2014 resolvedParameters[i] = element; | |
2015 nameNode.staticElement = element; | |
2016 } | |
2017 if (!usedNames.add(name)) { | |
2018 _resolver.reportErrorForNode( | |
2019 CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]); | |
2020 } | |
2021 } else { | |
2022 if (argument is SimpleIdentifier && argument.name.isEmpty) { | |
2023 noBlankArguments = false; | |
2024 } | |
2025 positionalArgumentCount++; | |
2026 if (unnamedIndex < unnamedParameterCount) { | |
2027 resolvedParameters[i] = unnamedParameters[unnamedIndex++]; | |
2028 } | |
2029 } | |
2030 } | |
2031 if (positionalArgumentCount < requiredParameters.length && | |
2032 noBlankArguments) { | |
2033 ErrorCode errorCode = (reportError | |
2034 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS | |
2035 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS); | |
2036 _resolver.reportErrorForNode(errorCode, argumentList, | |
2037 [requiredParameters.length, positionalArgumentCount]); | |
2038 } else if (positionalArgumentCount > unnamedParameterCount && | |
2039 noBlankArguments) { | |
2040 ErrorCode errorCode = (reportError | |
2041 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS | |
2042 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS); | |
2043 _resolver.reportErrorForNode(errorCode, argumentList, | |
2044 [unnamedParameterCount, positionalArgumentCount]); | |
2045 } | |
2046 return resolvedParameters; | |
2047 } | 1963 } |
2048 | 1964 |
2049 void _resolveBinaryExpression(BinaryExpression node, String methodName) { | 1965 void _resolveBinaryExpression(BinaryExpression node, String methodName) { |
2050 Expression leftOperand = node.leftOperand; | 1966 Expression leftOperand = node.leftOperand; |
2051 if (leftOperand != null) { | 1967 if (leftOperand != null) { |
2052 DartType staticType = _getStaticType(leftOperand); | 1968 DartType staticType = _getStaticType(leftOperand); |
2053 MethodElement staticMethod = | 1969 MethodElement staticMethod = |
2054 _lookUpMethod(leftOperand, staticType, methodName); | 1970 _lookUpMethod(leftOperand, staticType, methodName); |
2055 node.staticElement = staticMethod; | 1971 node.staticElement = staticMethod; |
2056 DartType propagatedType = _getPropagatedType(leftOperand); | 1972 DartType propagatedType = _getPropagatedType(leftOperand); |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2644 | 2560 |
2645 @override | 2561 @override |
2646 Element get staticElement => null; | 2562 Element get staticElement => null; |
2647 | 2563 |
2648 @override | 2564 @override |
2649 accept(AstVisitor visitor) => null; | 2565 accept(AstVisitor visitor) => null; |
2650 | 2566 |
2651 @override | 2567 @override |
2652 void visitChildren(AstVisitor visitor) {} | 2568 void visitChildren(AstVisitor visitor) {} |
2653 } | 2569 } |
OLD | NEW |