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 = |
| 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 if (propagatedInvokeType != null && |
| 656 propagatedInvokeType.isMoreSpecificThan(staticInvokeType)) { |
| 657 // Don't store the propagated invoke type unless it's more specific than |
| 658 // the static type. We still need to record the propagated parameter |
| 659 // elements however, as that is used for the propagatedType downwards |
| 660 // inference of lambda parameters. |
| 661 node.propagatedInvokeType = propagatedInvokeType; |
| 662 } |
| 663 |
689 ArgumentList argumentList = node.argumentList; | 664 ArgumentList argumentList = node.argumentList; |
690 if (staticElement != null) { | 665 if (staticInvokeType != null) { |
691 List<ParameterElement> parameters = | 666 List<ParameterElement> parameters = |
692 _computeCorrespondingParameters(argumentList, staticElement); | 667 _computeCorrespondingParameters(argumentList, staticInvokeType); |
693 if (parameters != null) { | 668 if (parameters != null) { |
694 argumentList.correspondingStaticParameters = parameters; | 669 argumentList.correspondingStaticParameters = parameters; |
695 } | 670 } |
696 } | 671 } |
697 if (propagatedElement != null) { | 672 if (propagatedInvokeType != null) { |
698 List<ParameterElement> parameters = | 673 List<ParameterElement> parameters = |
699 _computeCorrespondingParameters(argumentList, propagatedElement); | 674 _computeCorrespondingParameters(argumentList, propagatedInvokeType); |
700 if (parameters != null) { | 675 if (parameters != null) { |
701 argumentList.correspondingPropagatedParameters = parameters; | 676 argumentList.correspondingPropagatedParameters = parameters; |
702 } | 677 } |
703 } | 678 } |
704 // | 679 // |
705 // Then check for error conditions. | 680 // Then check for error conditions. |
706 // | 681 // |
707 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); | 682 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); |
708 bool generatedWithTypePropagation = false; | 683 bool generatedWithTypePropagation = false; |
709 if (_enableHints && errorCode == null && staticElement == null) { | 684 if (_enableHints && errorCode == null && staticElement == null) { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 return false; | 1304 return false; |
1330 } | 1305 } |
1331 | 1306 |
1332 /** | 1307 /** |
1333 * Given an [argumentList] and the executable [element] that will be invoked | 1308 * Given an [argumentList] and the executable [element] that will be invoked |
1334 * using those arguments, compute the list of parameters that correspond to | 1309 * using those arguments, compute the list of parameters that correspond to |
1335 * the list of arguments. Return the parameters that correspond to the | 1310 * the list of arguments. Return the parameters that correspond to the |
1336 * arguments, or `null` if no correspondence could be computed. | 1311 * arguments, or `null` if no correspondence could be computed. |
1337 */ | 1312 */ |
1338 List<ParameterElement> _computeCorrespondingParameters( | 1313 List<ParameterElement> _computeCorrespondingParameters( |
1339 ArgumentList argumentList, Element element) { | 1314 ArgumentList argumentList, DartType type) { |
1340 if (element is PropertyAccessorElement) { | 1315 if (type is InterfaceType) { |
1341 // | 1316 MethodElement callMethod = |
1342 // This is an invocation of the call method defined on the value returned | 1317 type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary); |
1343 // by the getter. | 1318 if (callMethod != null) { |
1344 // | 1319 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 } | 1320 } |
1359 } else if (element is ExecutableElement) { | 1321 } else if (type is FunctionType) { |
1360 return _resolveArgumentsToFunction(false, argumentList, element); | 1322 return _resolveArgumentsToParameters( |
1361 } else if (element is VariableElement) { | 1323 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 } | 1324 } |
1378 return null; | 1325 return null; |
1379 } | 1326 } |
1380 | 1327 |
1381 /** | 1328 /** |
1382 * If the given [element] is a setter, return the getter associated with it. | 1329 * If the given [element] is a setter, return the getter associated with it. |
1383 * Otherwise, return the element unchanged. | 1330 * Otherwise, return the element unchanged. |
1384 */ | 1331 */ |
1385 Element _convertSetterToGetter(Element element) { | 1332 Element _convertSetterToGetter(Element element) { |
1386 // TODO(brianwilkerson) Determine whether and why the element could ever be | 1333 // 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) { | 1454 if (staticType is FunctionType) { |
1508 // | 1455 // |
1509 // All function types are subtypes of 'Function', which is itself a | 1456 // All function types are subtypes of 'Function', which is itself a |
1510 // subclass of 'Object'. | 1457 // subclass of 'Object'. |
1511 // | 1458 // |
1512 staticType = _resolver.typeProvider.functionType; | 1459 staticType = _resolver.typeProvider.functionType; |
1513 } | 1460 } |
1514 return staticType; | 1461 return staticType; |
1515 } | 1462 } |
1516 | 1463 |
| 1464 DartType _computeMethodInvokeType(MethodInvocation node, Element element) { |
| 1465 if (element == null) { |
| 1466 return null; |
| 1467 } |
| 1468 |
| 1469 DartType invokeType; |
| 1470 if (element is PropertyAccessorElement) { |
| 1471 invokeType = element.returnType; |
| 1472 } else if (element is ExecutableElement) { |
| 1473 invokeType = element.type; |
| 1474 } else if (element is VariableElement) { |
| 1475 invokeType = _promoteManager.getStaticType(element); |
| 1476 } |
| 1477 |
| 1478 // |
| 1479 // Check for a generic method & apply type arguments if any were passed. |
| 1480 // |
| 1481 // TODO(jmesserly): support generic "call" methods on InterfaceType. |
| 1482 if (invokeType is FunctionType) { |
| 1483 FunctionType type = invokeType; |
| 1484 List<TypeParameterElement> parameters = type.typeFormals; |
| 1485 |
| 1486 NodeList<TypeName> arguments = node.typeArguments?.arguments; |
| 1487 if (arguments != null && arguments.length != parameters.length) { |
| 1488 // Wrong number of type arguments. Ignore them |
| 1489 arguments = null; |
| 1490 _resolver.reportErrorForNode( |
| 1491 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, |
| 1492 node.methodName, |
| 1493 [type, parameters.length, arguments?.length ?? 0]); |
| 1494 } |
| 1495 if (parameters.isNotEmpty) { |
| 1496 if (arguments == null) { |
| 1497 invokeType = _resolver.typeSystem.instantiateToBounds(type); |
| 1498 } else { |
| 1499 invokeType = type.instantiate(arguments.map((n) => n.type).toList()); |
| 1500 } |
| 1501 } |
| 1502 } |
| 1503 |
| 1504 return invokeType; |
| 1505 } |
| 1506 |
1517 /** | 1507 /** |
1518 * Return `true` if the given [expression] is a prefix for a deferred import. | 1508 * Return `true` if the given [expression] is a prefix for a deferred import. |
1519 */ | 1509 */ |
1520 bool _isDeferredPrefix(Expression expression) { | 1510 bool _isDeferredPrefix(Expression expression) { |
1521 if (expression is! SimpleIdentifier) { | 1511 if (expression is! SimpleIdentifier) { |
1522 return false; | 1512 return false; |
1523 } | 1513 } |
1524 Element element = (expression as SimpleIdentifier).staticElement; | 1514 Element element = (expression as SimpleIdentifier).staticElement; |
1525 if (element is! PrefixElement) { | 1515 if (element is! PrefixElement) { |
1526 return false; | 1516 return false; |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1941 [annotation.name]); | 1931 [annotation.name]); |
1942 } | 1932 } |
1943 // OK | 1933 // OK |
1944 return; | 1934 return; |
1945 } | 1935 } |
1946 | 1936 |
1947 /** | 1937 /** |
1948 * Given an [argumentList] and the [executableElement] that will be invoked | 1938 * Given an [argumentList] and the [executableElement] that will be invoked |
1949 * using those argument, compute the list of parameters that correspond to the | 1939 * using those argument, compute the list of parameters that correspond to the |
1950 * list of arguments. An error will be reported if any of the arguments cannot | 1940 * list of arguments. An error will be reported if any of the arguments cannot |
1951 * be matched to a parameter. The flag [reportError] should be `true` if a | 1941 * be matched to a parameter. The flag [reportAsError] should be `true` if a |
1952 * compile-time error should be reported; or `false` if a compile-time warning | 1942 * compile-time error should be reported; or `false` if a compile-time warning |
1953 * should be reported. Return the parameters that correspond to the arguments, | 1943 * should be reported. Return the parameters that correspond to the arguments, |
1954 * or `null` if no correspondence could be computed. | 1944 * or `null` if no correspondence could be computed. |
1955 */ | 1945 */ |
1956 List<ParameterElement> _resolveArgumentsToFunction(bool reportError, | 1946 List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError, |
1957 ArgumentList argumentList, ExecutableElement executableElement) { | 1947 ArgumentList argumentList, ExecutableElement executableElement) { |
1958 if (executableElement == null) { | 1948 if (executableElement == null) { |
1959 return null; | 1949 return null; |
1960 } | 1950 } |
1961 List<ParameterElement> parameters = executableElement.parameters; | 1951 List<ParameterElement> parameters = executableElement.parameters; |
1962 return _resolveArgumentsToParameters(reportError, argumentList, parameters); | 1952 return _resolveArgumentsToParameters( |
| 1953 reportAsError, argumentList, parameters); |
1963 } | 1954 } |
1964 | 1955 |
1965 /** | 1956 /** |
1966 * Given an [argumentList] and the [parameters] related to the element that | 1957 * Given an [argumentList] and the [parameters] related to the element that |
1967 * will be invoked using those arguments, compute the list of parameters that | 1958 * 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 | 1959 * 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] | 1960 * the arguments cannot be matched to a parameter. The flag [reportAsError] |
1970 * should be `true` if a compile-time error should be reported; or `false` if | 1961 * 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 | 1962 * a compile-time warning should be reported. Return the parameters that |
1972 * correspond to the arguments. | 1963 * correspond to the arguments. |
1973 */ | 1964 */ |
1974 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, | 1965 List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError, |
1975 ArgumentList argumentList, List<ParameterElement> parameters) { | 1966 ArgumentList argumentList, List<ParameterElement> parameters) { |
1976 List<ParameterElement> requiredParameters = new List<ParameterElement>(); | 1967 return ResolverVisitor.resolveArgumentsToParameters( |
1977 List<ParameterElement> positionalParameters = new List<ParameterElement>(); | 1968 argumentList, parameters, _resolver.reportErrorForNode, |
1978 HashMap<String, ParameterElement> namedParameters = | 1969 reportAsError: reportAsError); |
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 } | 1970 } |
2048 | 1971 |
2049 void _resolveBinaryExpression(BinaryExpression node, String methodName) { | 1972 void _resolveBinaryExpression(BinaryExpression node, String methodName) { |
2050 Expression leftOperand = node.leftOperand; | 1973 Expression leftOperand = node.leftOperand; |
2051 if (leftOperand != null) { | 1974 if (leftOperand != null) { |
2052 DartType staticType = _getStaticType(leftOperand); | 1975 DartType staticType = _getStaticType(leftOperand); |
2053 MethodElement staticMethod = | 1976 MethodElement staticMethod = |
2054 _lookUpMethod(leftOperand, staticType, methodName); | 1977 _lookUpMethod(leftOperand, staticType, methodName); |
2055 node.staticElement = staticMethod; | 1978 node.staticElement = staticMethod; |
2056 DartType propagatedType = _getPropagatedType(leftOperand); | 1979 DartType propagatedType = _getPropagatedType(leftOperand); |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2644 | 2567 |
2645 @override | 2568 @override |
2646 Element get staticElement => null; | 2569 Element get staticElement => null; |
2647 | 2570 |
2648 @override | 2571 @override |
2649 accept(AstVisitor visitor) => null; | 2572 accept(AstVisitor visitor) => null; |
2650 | 2573 |
2651 @override | 2574 @override |
2652 void visitChildren(AstVisitor visitor) {} | 2575 void visitChildren(AstVisitor visitor) {} |
2653 } | 2576 } |
OLD | NEW |