| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dev_compiler.src.checker.checker; | 5 library dev_compiler.src.checker.checker; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 import 'package:analyzer/src/generated/ast.dart'; | 8 import 'package:analyzer/src/generated/ast.dart'; |
| 9 import 'package:analyzer/src/generated/element.dart'; | 9 import 'package:analyzer/src/generated/element.dart'; |
| 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; | 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 arg = (arg as NamedExpression).expression; | 538 arg = (arg as NamedExpression).expression; |
| 539 } | 539 } |
| 540 checkAssignment(arg, expectedType); | 540 checkAssignment(arg, expectedType); |
| 541 } | 541 } |
| 542 | 542 |
| 543 void checkFunctionApplication( | 543 void checkFunctionApplication( |
| 544 Expression node, Expression f, ArgumentList list) { | 544 Expression node, Expression f, ArgumentList list) { |
| 545 if (_rules.isDynamicCall(f)) { | 545 if (_rules.isDynamicCall(f)) { |
| 546 // If f is Function and this is a method invocation, we should have | 546 // If f is Function and this is a method invocation, we should have |
| 547 // gotten an analyzer error, so no need to issue another error. | 547 // gotten an analyzer error, so no need to issue another error. |
| 548 _recordDynamicInvoke(node); | 548 _recordDynamicInvoke(node, f); |
| 549 } else { | 549 } else { |
| 550 checkArgumentList(list, _rules.getTypeAsCaller(f)); | 550 checkArgumentList(list, _rules.getTypeAsCaller(f)); |
| 551 } | 551 } |
| 552 } | 552 } |
| 553 | 553 |
| 554 @override | 554 @override |
| 555 void visitMethodInvocation(MethodInvocation node) { | 555 visitMethodInvocation(MethodInvocation node) { |
| 556 checkFunctionApplication(node, node.methodName, node.argumentList); | 556 var target = node.realTarget; |
| 557 if (_rules.isDynamicTarget(target)) { |
| 558 _recordDynamicInvoke(node, target); |
| 559 |
| 560 // Mark the tear-off as being dynamic, too. This lets us distinguish |
| 561 // cases like: |
| 562 // |
| 563 // dynamic d; |
| 564 // d.someMethod(...); // the whole method call must be a dynamic send. |
| 565 // |
| 566 // ... from case like: |
| 567 // |
| 568 // SomeType s; |
| 569 // s.someDynamicField(...); // static get, followed by dynamic call. |
| 570 // |
| 571 // The first case is handled here, the second case is handled below when |
| 572 // we call [checkFunctionApplication]. |
| 573 DynamicInvoke.set(node.methodName, true); |
| 574 } else { |
| 575 checkFunctionApplication(node, node.methodName, node.argumentList); |
| 576 } |
| 557 node.visitChildren(this); | 577 node.visitChildren(this); |
| 558 } | 578 } |
| 559 | 579 |
| 560 @override | 580 @override |
| 561 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 581 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 562 checkFunctionApplication(node, node.function, node.argumentList); | 582 checkFunctionApplication(node, node.function, node.argumentList); |
| 563 node.visitChildren(this); | 583 node.visitChildren(this); |
| 564 } | 584 } |
| 565 | 585 |
| 566 @override | 586 @override |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 } | 635 } |
| 616 | 636 |
| 617 @override | 637 @override |
| 618 void visitReturnStatement(ReturnStatement node) { | 638 void visitReturnStatement(ReturnStatement node) { |
| 619 _checkReturn(node.expression, node); | 639 _checkReturn(node.expression, node); |
| 620 node.visitChildren(this); | 640 node.visitChildren(this); |
| 621 } | 641 } |
| 622 | 642 |
| 623 @override | 643 @override |
| 624 void visitPropertyAccess(PropertyAccess node) { | 644 void visitPropertyAccess(PropertyAccess node) { |
| 625 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) { | 645 var target = node.realTarget; |
| 626 _recordDynamicInvoke(node); | 646 if (_rules.isDynamicTarget(target)) { |
| 647 _recordDynamicInvoke(node, target); |
| 627 } | 648 } |
| 628 node.visitChildren(this); | 649 node.visitChildren(this); |
| 629 } | 650 } |
| 630 | 651 |
| 631 @override | 652 @override |
| 632 void visitPrefixedIdentifier(PrefixedIdentifier node) { | 653 void visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 633 final target = node.prefix; | 654 final target = node.prefix; |
| 634 if (_rules.isDynamicTarget(target)) { | 655 if (_rules.isDynamicTarget(target)) { |
| 635 _recordDynamicInvoke(node); | 656 _recordDynamicInvoke(node, target); |
| 636 } | 657 } |
| 637 node.visitChildren(this); | 658 node.visitChildren(this); |
| 638 } | 659 } |
| 639 | 660 |
| 640 @override | 661 @override |
| 641 void visitDefaultFormalParameter(DefaultFormalParameter node) { | 662 void visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 642 _visitMaybeConst(node, (node) { | 663 _visitMaybeConst(node, (node) { |
| 643 // Check that defaults have the proper subtype. | 664 // Check that defaults have the proper subtype. |
| 644 var parameter = node.parameter; | 665 var parameter = node.parameter; |
| 645 var parameterType = _rules.elementType(parameter.element); | 666 var parameterType = _rules.elementType(parameter.element); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 _checkUnary(node); | 788 _checkUnary(node); |
| 768 node.visitChildren(this); | 789 node.visitChildren(this); |
| 769 } | 790 } |
| 770 | 791 |
| 771 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) { | 792 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) { |
| 772 var op = node.operator; | 793 var op = node.operator; |
| 773 if (op.isUserDefinableOperator || | 794 if (op.isUserDefinableOperator || |
| 774 op.type == TokenType.PLUS_PLUS || | 795 op.type == TokenType.PLUS_PLUS || |
| 775 op.type == TokenType.MINUS_MINUS) { | 796 op.type == TokenType.MINUS_MINUS) { |
| 776 if (_rules.isDynamicTarget(node.operand)) { | 797 if (_rules.isDynamicTarget(node.operand)) { |
| 777 _recordDynamicInvoke(node); | 798 _recordDynamicInvoke(node, node.operand); |
| 778 } | 799 } |
| 779 // For ++ and --, even if it is not dynamic, we still need to check | 800 // For ++ and --, even if it is not dynamic, we still need to check |
| 780 // that the user defined method accepts an `int` as the RHS. | 801 // that the user defined method accepts an `int` as the RHS. |
| 781 // We assume Analyzer has done this already. | 802 // We assume Analyzer has done this already. |
| 782 } | 803 } |
| 783 } | 804 } |
| 784 | 805 |
| 785 @override | 806 @override |
| 786 void visitBinaryExpression(BinaryExpression node) { | 807 void visitBinaryExpression(BinaryExpression node) { |
| 787 var op = node.operator; | 808 var op = node.operator; |
| 788 if (op.isUserDefinableOperator) { | 809 if (op.isUserDefinableOperator) { |
| 789 if (_rules.isDynamicTarget(node.leftOperand)) { | 810 if (_rules.isDynamicTarget(node.leftOperand)) { |
| 790 // Dynamic invocation | 811 // Dynamic invocation |
| 791 // TODO(vsm): Move this logic to the resolver? | 812 // TODO(vsm): Move this logic to the resolver? |
| 792 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) { | 813 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) { |
| 793 _recordDynamicInvoke(node); | 814 _recordDynamicInvoke(node, node.leftOperand); |
| 794 } | 815 } |
| 795 } else { | 816 } else { |
| 796 var element = node.staticElement; | 817 var element = node.staticElement; |
| 797 // Method invocation. | 818 // Method invocation. |
| 798 if (element is MethodElement) { | 819 if (element is MethodElement) { |
| 799 var type = element.type as FunctionType; | 820 var type = element.type as FunctionType; |
| 800 // Analyzer should enforce number of parameter types, but check in | 821 // Analyzer should enforce number of parameter types, but check in |
| 801 // case we have erroneous input. | 822 // case we have erroneous input. |
| 802 if (type.normalParameterTypes.isNotEmpty) { | 823 if (type.normalParameterTypes.isNotEmpty) { |
| 803 checkArgument(node.rightOperand, type.normalParameterTypes[0]); | 824 checkArgument(node.rightOperand, type.normalParameterTypes[0]); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 824 } | 845 } |
| 825 | 846 |
| 826 @override | 847 @override |
| 827 void visitConditionalExpression(ConditionalExpression node) { | 848 void visitConditionalExpression(ConditionalExpression node) { |
| 828 checkBoolean(node.condition); | 849 checkBoolean(node.condition); |
| 829 node.visitChildren(this); | 850 node.visitChildren(this); |
| 830 } | 851 } |
| 831 | 852 |
| 832 @override | 853 @override |
| 833 void visitIndexExpression(IndexExpression node) { | 854 void visitIndexExpression(IndexExpression node) { |
| 834 if (_rules.isDynamicTarget(node.target)) { | 855 var target = node.realTarget; |
| 835 _recordDynamicInvoke(node); | 856 if (_rules.isDynamicTarget(target)) { |
| 857 _recordDynamicInvoke(node, target); |
| 836 } else { | 858 } else { |
| 837 var element = node.staticElement; | 859 var element = node.staticElement; |
| 838 if (element is MethodElement) { | 860 if (element is MethodElement) { |
| 839 var type = element.type as FunctionType; | 861 var type = element.type as FunctionType; |
| 840 // Analyzer should enforce number of parameter types, but check in | 862 // Analyzer should enforce number of parameter types, but check in |
| 841 // case we have erroneous input. | 863 // case we have erroneous input. |
| 842 if (type.normalParameterTypes.isNotEmpty) { | 864 if (type.normalParameterTypes.isNotEmpty) { |
| 843 checkArgument(node.index, type.normalParameterTypes[0]); | 865 checkArgument(node.index, type.normalParameterTypes[0]); |
| 844 } | 866 } |
| 845 } else { | 867 } else { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 } | 912 } |
| 891 return normalReturnType; | 913 return normalReturnType; |
| 892 } | 914 } |
| 893 | 915 |
| 894 void _checkCompoundAssignment(AssignmentExpression expr) { | 916 void _checkCompoundAssignment(AssignmentExpression expr) { |
| 895 var op = expr.operator.type; | 917 var op = expr.operator.type; |
| 896 assert(op.isAssignmentOperator && op != TokenType.EQ); | 918 assert(op.isAssignmentOperator && op != TokenType.EQ); |
| 897 var methodElement = expr.staticElement; | 919 var methodElement = expr.staticElement; |
| 898 if (methodElement == null) { | 920 if (methodElement == null) { |
| 899 // Dynamic invocation | 921 // Dynamic invocation |
| 900 _recordDynamicInvoke(expr); | 922 _recordDynamicInvoke(expr, expr.leftHandSide); |
| 901 } else { | 923 } else { |
| 902 // Sanity check the operator | 924 // Sanity check the operator |
| 903 assert(methodElement.isOperator); | 925 assert(methodElement.isOperator); |
| 904 var functionType = methodElement.type; | 926 var functionType = methodElement.type; |
| 905 var paramTypes = functionType.normalParameterTypes; | 927 var paramTypes = functionType.normalParameterTypes; |
| 906 assert(paramTypes.length == 1); | 928 assert(paramTypes.length == 1); |
| 907 assert(functionType.namedParameterTypes.isEmpty); | 929 assert(functionType.namedParameterTypes.isEmpty); |
| 908 assert(functionType.optionalParameterTypes.isEmpty); | 930 assert(functionType.optionalParameterTypes.isEmpty); |
| 909 | 931 |
| 910 // Check the lhs type | 932 // Check the lhs type |
| (...skipping 23 matching lines...) Expand all Loading... |
| 934 // Check the rhs type | 956 // Check the rhs type |
| 935 if (staticInfo is! CoercionInfo) { | 957 if (staticInfo is! CoercionInfo) { |
| 936 var paramType = paramTypes.first; | 958 var paramType = paramTypes.first; |
| 937 staticInfo = _rules.checkAssignment( | 959 staticInfo = _rules.checkAssignment( |
| 938 expr.rightHandSide, paramType, _constantContext); | 960 expr.rightHandSide, paramType, _constantContext); |
| 939 _recordMessage(staticInfo); | 961 _recordMessage(staticInfo); |
| 940 } | 962 } |
| 941 } | 963 } |
| 942 } | 964 } |
| 943 | 965 |
| 944 void _recordDynamicInvoke(AstNode node) { | 966 void _recordDynamicInvoke(AstNode node, AstNode target) { |
| 945 _reporter.log(new DynamicInvoke(_rules, node)); | 967 var dinvoke = new DynamicInvoke(_rules, node); |
| 968 _reporter.log(dinvoke); |
| 969 // TODO(jmesserly): we may eventually want to record if the whole operation |
| 970 // (node) was dynamic, rather than the target, but this is an easier fit |
| 971 // with what we used to do. |
| 972 DynamicInvoke.set(target, true); |
| 946 } | 973 } |
| 947 | 974 |
| 948 void _recordMessage(StaticInfo info) { | 975 void _recordMessage(StaticInfo info) { |
| 949 if (info == null) return; | 976 if (info == null) return; |
| 950 if (info.level >= logger.Level.SEVERE) _failure = true; | 977 if (info.level >= logger.Level.SEVERE) _failure = true; |
| 951 _reporter.log(info); | 978 _reporter.log(info); |
| 952 if (info is CoercionInfo) { | 979 if (info is CoercionInfo) { |
| 953 assert(CoercionInfo.get(info.node) == null); | 980 assert(CoercionInfo.get(info.node) == null); |
| 954 CoercionInfo.set(info.node, info); | 981 CoercionInfo.set(info.node, info); |
| 955 } | 982 } |
| 956 } | 983 } |
| 957 } | 984 } |
| OLD | NEW |