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 |