Chromium Code Reviews| 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 // Mark the call as being dynamic as well. | |
| 560 DynamicInvoke.set(node.methodName, true); | |
|
Jennifer Messerly
2015/06/12 18:18:09
we are interesting both in whether the method call
Leaf
2015/06/12 20:13:23
This is a little obscure, maybe worth a bit more e
Jennifer Messerly
2015/06/12 20:22:28
sure. will add. For your info, what happens is we
| |
| 561 } else { | |
| 562 checkFunctionApplication(node, node.methodName, node.argumentList); | |
| 563 } | |
| 557 node.visitChildren(this); | 564 node.visitChildren(this); |
| 558 } | 565 } |
| 559 | 566 |
| 560 @override | 567 @override |
| 561 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 568 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 562 checkFunctionApplication(node, node.function, node.argumentList); | 569 checkFunctionApplication(node, node.function, node.argumentList); |
| 563 node.visitChildren(this); | 570 node.visitChildren(this); |
| 564 } | 571 } |
| 565 | 572 |
| 566 @override | 573 @override |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 615 } | 622 } |
| 616 | 623 |
| 617 @override | 624 @override |
| 618 void visitReturnStatement(ReturnStatement node) { | 625 void visitReturnStatement(ReturnStatement node) { |
| 619 _checkReturn(node.expression, node); | 626 _checkReturn(node.expression, node); |
| 620 node.visitChildren(this); | 627 node.visitChildren(this); |
| 621 } | 628 } |
| 622 | 629 |
| 623 @override | 630 @override |
| 624 void visitPropertyAccess(PropertyAccess node) { | 631 void visitPropertyAccess(PropertyAccess node) { |
| 625 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) { | 632 var target = node.realTarget; |
|
Jennifer Messerly
2015/06/12 18:18:09
bug fix: cascade dinvoke not reported
| |
| 626 _recordDynamicInvoke(node); | 633 if (_rules.isDynamicTarget(target)) { |
| 634 _recordDynamicInvoke(node, target); | |
| 627 } | 635 } |
| 628 node.visitChildren(this); | 636 node.visitChildren(this); |
| 629 } | 637 } |
| 630 | 638 |
| 631 @override | 639 @override |
| 632 void visitPrefixedIdentifier(PrefixedIdentifier node) { | 640 void visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 633 final target = node.prefix; | 641 final target = node.prefix; |
| 634 if (_rules.isDynamicTarget(target)) { | 642 if (_rules.isDynamicTarget(target)) { |
| 635 _recordDynamicInvoke(node); | 643 _recordDynamicInvoke(node, target); |
| 636 } | 644 } |
| 637 node.visitChildren(this); | 645 node.visitChildren(this); |
| 638 } | 646 } |
| 639 | 647 |
| 640 @override | 648 @override |
| 641 void visitDefaultFormalParameter(DefaultFormalParameter node) { | 649 void visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 642 _visitMaybeConst(node, (node) { | 650 _visitMaybeConst(node, (node) { |
| 643 // Check that defaults have the proper subtype. | 651 // Check that defaults have the proper subtype. |
| 644 var parameter = node.parameter; | 652 var parameter = node.parameter; |
| 645 var parameterType = _rules.elementType(parameter.element); | 653 var parameterType = _rules.elementType(parameter.element); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 767 _checkUnary(node); | 775 _checkUnary(node); |
| 768 node.visitChildren(this); | 776 node.visitChildren(this); |
| 769 } | 777 } |
| 770 | 778 |
| 771 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) { | 779 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) { |
| 772 var op = node.operator; | 780 var op = node.operator; |
| 773 if (op.isUserDefinableOperator || | 781 if (op.isUserDefinableOperator || |
| 774 op.type == TokenType.PLUS_PLUS || | 782 op.type == TokenType.PLUS_PLUS || |
| 775 op.type == TokenType.MINUS_MINUS) { | 783 op.type == TokenType.MINUS_MINUS) { |
| 776 if (_rules.isDynamicTarget(node.operand)) { | 784 if (_rules.isDynamicTarget(node.operand)) { |
| 777 _recordDynamicInvoke(node); | 785 _recordDynamicInvoke(node, node.operand); |
| 778 } | 786 } |
| 779 // For ++ and --, even if it is not dynamic, we still need to check | 787 // 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. | 788 // that the user defined method accepts an `int` as the RHS. |
| 781 // We assume Analyzer has done this already. | 789 // We assume Analyzer has done this already. |
| 782 } | 790 } |
| 783 } | 791 } |
| 784 | 792 |
| 785 @override | 793 @override |
| 786 void visitBinaryExpression(BinaryExpression node) { | 794 void visitBinaryExpression(BinaryExpression node) { |
| 787 var op = node.operator; | 795 var op = node.operator; |
| 788 if (op.isUserDefinableOperator) { | 796 if (op.isUserDefinableOperator) { |
| 789 if (_rules.isDynamicTarget(node.leftOperand)) { | 797 if (_rules.isDynamicTarget(node.leftOperand)) { |
| 790 // Dynamic invocation | 798 // Dynamic invocation |
| 791 // TODO(vsm): Move this logic to the resolver? | 799 // TODO(vsm): Move this logic to the resolver? |
| 792 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) { | 800 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) { |
| 793 _recordDynamicInvoke(node); | 801 _recordDynamicInvoke(node, node.leftOperand); |
| 794 } | 802 } |
| 795 } else { | 803 } else { |
| 796 var element = node.staticElement; | 804 var element = node.staticElement; |
| 797 // Method invocation. | 805 // Method invocation. |
| 798 if (element is MethodElement) { | 806 if (element is MethodElement) { |
| 799 var type = element.type as FunctionType; | 807 var type = element.type as FunctionType; |
| 800 // Analyzer should enforce number of parameter types, but check in | 808 // Analyzer should enforce number of parameter types, but check in |
| 801 // case we have erroneous input. | 809 // case we have erroneous input. |
| 802 if (type.normalParameterTypes.isNotEmpty) { | 810 if (type.normalParameterTypes.isNotEmpty) { |
| 803 checkArgument(node.rightOperand, type.normalParameterTypes[0]); | 811 checkArgument(node.rightOperand, type.normalParameterTypes[0]); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 824 } | 832 } |
| 825 | 833 |
| 826 @override | 834 @override |
| 827 void visitConditionalExpression(ConditionalExpression node) { | 835 void visitConditionalExpression(ConditionalExpression node) { |
| 828 checkBoolean(node.condition); | 836 checkBoolean(node.condition); |
| 829 node.visitChildren(this); | 837 node.visitChildren(this); |
| 830 } | 838 } |
| 831 | 839 |
| 832 @override | 840 @override |
| 833 void visitIndexExpression(IndexExpression node) { | 841 void visitIndexExpression(IndexExpression node) { |
| 834 if (_rules.isDynamicTarget(node.target)) { | 842 var target = node.realTarget; |
|
Jennifer Messerly
2015/06/12 18:18:09
bug fix: cascade dinvoke not reported
| |
| 835 _recordDynamicInvoke(node); | 843 if (_rules.isDynamicTarget(target)) { |
| 844 _recordDynamicInvoke(node, target); | |
| 836 } else { | 845 } else { |
| 837 var element = node.staticElement; | 846 var element = node.staticElement; |
| 838 if (element is MethodElement) { | 847 if (element is MethodElement) { |
| 839 var type = element.type as FunctionType; | 848 var type = element.type as FunctionType; |
| 840 // Analyzer should enforce number of parameter types, but check in | 849 // Analyzer should enforce number of parameter types, but check in |
| 841 // case we have erroneous input. | 850 // case we have erroneous input. |
| 842 if (type.normalParameterTypes.isNotEmpty) { | 851 if (type.normalParameterTypes.isNotEmpty) { |
| 843 checkArgument(node.index, type.normalParameterTypes[0]); | 852 checkArgument(node.index, type.normalParameterTypes[0]); |
| 844 } | 853 } |
| 845 } else { | 854 } else { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 890 } | 899 } |
| 891 return normalReturnType; | 900 return normalReturnType; |
| 892 } | 901 } |
| 893 | 902 |
| 894 void _checkCompoundAssignment(AssignmentExpression expr) { | 903 void _checkCompoundAssignment(AssignmentExpression expr) { |
| 895 var op = expr.operator.type; | 904 var op = expr.operator.type; |
| 896 assert(op.isAssignmentOperator && op != TokenType.EQ); | 905 assert(op.isAssignmentOperator && op != TokenType.EQ); |
| 897 var methodElement = expr.staticElement; | 906 var methodElement = expr.staticElement; |
| 898 if (methodElement == null) { | 907 if (methodElement == null) { |
| 899 // Dynamic invocation | 908 // Dynamic invocation |
| 900 _recordDynamicInvoke(expr); | 909 _recordDynamicInvoke(expr, expr.leftHandSide); |
| 901 } else { | 910 } else { |
| 902 // Sanity check the operator | 911 // Sanity check the operator |
| 903 assert(methodElement.isOperator); | 912 assert(methodElement.isOperator); |
| 904 var functionType = methodElement.type; | 913 var functionType = methodElement.type; |
| 905 var paramTypes = functionType.normalParameterTypes; | 914 var paramTypes = functionType.normalParameterTypes; |
| 906 assert(paramTypes.length == 1); | 915 assert(paramTypes.length == 1); |
| 907 assert(functionType.namedParameterTypes.isEmpty); | 916 assert(functionType.namedParameterTypes.isEmpty); |
| 908 assert(functionType.optionalParameterTypes.isEmpty); | 917 assert(functionType.optionalParameterTypes.isEmpty); |
| 909 | 918 |
| 910 // Check the lhs type | 919 // Check the lhs type |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 934 // Check the rhs type | 943 // Check the rhs type |
| 935 if (staticInfo is! CoercionInfo) { | 944 if (staticInfo is! CoercionInfo) { |
| 936 var paramType = paramTypes.first; | 945 var paramType = paramTypes.first; |
| 937 staticInfo = _rules.checkAssignment( | 946 staticInfo = _rules.checkAssignment( |
| 938 expr.rightHandSide, paramType, _constantContext); | 947 expr.rightHandSide, paramType, _constantContext); |
| 939 _recordMessage(staticInfo); | 948 _recordMessage(staticInfo); |
| 940 } | 949 } |
| 941 } | 950 } |
| 942 } | 951 } |
| 943 | 952 |
| 944 void _recordDynamicInvoke(AstNode node) { | 953 void _recordDynamicInvoke(AstNode node, AstNode target) { |
| 945 _reporter.log(new DynamicInvoke(_rules, node)); | 954 var dinvoke = new DynamicInvoke(_rules, node); |
| 955 _reporter.log(dinvoke); | |
| 956 // TODO(jmesserly): we may eventually want to record if the whole operation | |
| 957 // (node) was dynamic, rather than the target, but this is an easier fit | |
| 958 // with what we used to do. | |
| 959 DynamicInvoke.set(target, true); | |
| 946 } | 960 } |
| 947 | 961 |
| 948 void _recordMessage(StaticInfo info) { | 962 void _recordMessage(StaticInfo info) { |
| 949 if (info == null) return; | 963 if (info == null) return; |
| 950 if (info.level >= logger.Level.SEVERE) _failure = true; | 964 if (info.level >= logger.Level.SEVERE) _failure = true; |
| 951 _reporter.log(info); | 965 _reporter.log(info); |
| 952 if (info is CoercionInfo) { | 966 if (info is CoercionInfo) { |
| 953 assert(CoercionInfo.get(info.node) == null); | 967 assert(CoercionInfo.get(info.node) == null); |
| 954 CoercionInfo.set(info.node, info); | 968 CoercionInfo.set(info.node, info); |
| 955 } | 969 } |
| 956 } | 970 } |
| 957 } | 971 } |
| OLD | NEW |