Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: pkg/analyzer/lib/src/generated/element_resolver.dart

Issue 1568643002: clean up generic methods in resolution (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 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
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
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): support generic "call" methods on InterfaceType.
1475 if (invokeType is FunctionType) {
1476 FunctionType type = invokeType;
1477 List<TypeParameterElement> parameters = type.typeFormals;
1478
1479 NodeList<TypeName> arguments = node.typeArguments?.arguments;
1480 if (arguments != null && arguments.length != parameters.length) {
1481 // Wrong number of type arguments. Ignore them
1482 arguments = null;
1483 _resolver.reportErrorForNode(
1484 StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
1485 node.methodName,
1486 [type, parameters.length, arguments?.length ?? 0]);
1487 }
1488 if (parameters.isNotEmpty) {
1489 if (arguments == null) {
1490 invokeType = _resolver.typeSystem.instantiateToBounds(type);
1491 } else {
1492 invokeType = type.instantiate(arguments.map((n) => n.type).toList());
1493 }
1494 }
1495 }
1496
1497 return invokeType;
1498 }
1499
1517 /** 1500 /**
1518 * Return `true` if the given [expression] is a prefix for a deferred import. 1501 * Return `true` if the given [expression] is a prefix for a deferred import.
1519 */ 1502 */
1520 bool _isDeferredPrefix(Expression expression) { 1503 bool _isDeferredPrefix(Expression expression) {
1521 if (expression is! SimpleIdentifier) { 1504 if (expression is! SimpleIdentifier) {
1522 return false; 1505 return false;
1523 } 1506 }
1524 Element element = (expression as SimpleIdentifier).staticElement; 1507 Element element = (expression as SimpleIdentifier).staticElement;
1525 if (element is! PrefixElement) { 1508 if (element is! PrefixElement) {
1526 return false; 1509 return false;
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after
1941 [annotation.name]); 1924 [annotation.name]);
1942 } 1925 }
1943 // OK 1926 // OK
1944 return; 1927 return;
1945 } 1928 }
1946 1929
1947 /** 1930 /**
1948 * Given an [argumentList] and the [executableElement] that will be invoked 1931 * Given an [argumentList] and the [executableElement] that will be invoked
1949 * using those argument, compute the list of parameters that correspond to the 1932 * 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 1933 * 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 1934 * 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 1935 * 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, 1936 * should be reported. Return the parameters that correspond to the arguments,
1954 * or `null` if no correspondence could be computed. 1937 * or `null` if no correspondence could be computed.
1955 */ 1938 */
1956 List<ParameterElement> _resolveArgumentsToFunction(bool reportError, 1939 List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
1957 ArgumentList argumentList, ExecutableElement executableElement) { 1940 ArgumentList argumentList, ExecutableElement executableElement) {
1958 if (executableElement == null) { 1941 if (executableElement == null) {
1959 return null; 1942 return null;
1960 } 1943 }
1961 List<ParameterElement> parameters = executableElement.parameters; 1944 List<ParameterElement> parameters = executableElement.parameters;
1962 return _resolveArgumentsToParameters(reportError, argumentList, parameters); 1945 return _resolveArgumentsToParameters(reportAsError, argumentList, parameters );
1963 } 1946 }
1964 1947
1965 /** 1948 /**
1966 * Given an [argumentList] and the [parameters] related to the element that 1949 * Given an [argumentList] and the [parameters] related to the element that
1967 * will be invoked using those arguments, compute the list of parameters that 1950 * 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 1951 * 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] 1952 * 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 1953 * 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 1954 * a compile-time warning should be reported. Return the parameters that
1972 * correspond to the arguments. 1955 * correspond to the arguments.
1973 */ 1956 */
1974 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, 1957 List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
1975 ArgumentList argumentList, List<ParameterElement> parameters) { 1958 ArgumentList argumentList, List<ParameterElement> parameters) {
1976 List<ParameterElement> requiredParameters = new List<ParameterElement>(); 1959 return ResolverVisitor.resolveArgumentsToParameters(
1977 List<ParameterElement> positionalParameters = new List<ParameterElement>(); 1960 argumentList, parameters, _resolver.reportErrorForNode,
1978 HashMap<String, ParameterElement> namedParameters = 1961 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 } 1962 }
2048 1963
2049 void _resolveBinaryExpression(BinaryExpression node, String methodName) { 1964 void _resolveBinaryExpression(BinaryExpression node, String methodName) {
2050 Expression leftOperand = node.leftOperand; 1965 Expression leftOperand = node.leftOperand;
2051 if (leftOperand != null) { 1966 if (leftOperand != null) {
2052 DartType staticType = _getStaticType(leftOperand); 1967 DartType staticType = _getStaticType(leftOperand);
2053 MethodElement staticMethod = 1968 MethodElement staticMethod =
2054 _lookUpMethod(leftOperand, staticType, methodName); 1969 _lookUpMethod(leftOperand, staticType, methodName);
2055 node.staticElement = staticMethod; 1970 node.staticElement = staticMethod;
2056 DartType propagatedType = _getPropagatedType(leftOperand); 1971 DartType propagatedType = _getPropagatedType(leftOperand);
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
2644 2559
2645 @override 2560 @override
2646 Element get staticElement => null; 2561 Element get staticElement => null;
2647 2562
2648 @override 2563 @override
2649 accept(AstVisitor visitor) => null; 2564 accept(AstVisitor visitor) => null;
2650 2565
2651 @override 2566 @override
2652 void visitChildren(AstVisitor visitor) {} 2567 void visitChildren(AstVisitor visitor) {}
2653 } 2568 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698