| 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 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 // gotten an analyzer error, so no need to issue another error. | 519 // gotten an analyzer error, so no need to issue another error. |
| 520 _recordDynamicInvoke(node, f); | 520 _recordDynamicInvoke(node, f); |
| 521 } else { | 521 } else { |
| 522 checkArgumentList(list, rules.getTypeAsCaller(f)); | 522 checkArgumentList(list, rules.getTypeAsCaller(f)); |
| 523 } | 523 } |
| 524 } | 524 } |
| 525 | 525 |
| 526 @override | 526 @override |
| 527 visitMethodInvocation(MethodInvocation node) { | 527 visitMethodInvocation(MethodInvocation node) { |
| 528 var target = node.realTarget; | 528 var target = node.realTarget; |
| 529 if (rules.isDynamicTarget(target)) { | 529 if (rules.isDynamicTarget(target) && |
| 530 !_isObjectMethod(node, node.methodName)) { |
| 530 _recordDynamicInvoke(node, target); | 531 _recordDynamicInvoke(node, target); |
| 531 | 532 |
| 532 // Mark the tear-off as being dynamic, too. This lets us distinguish | 533 // Mark the tear-off as being dynamic, too. This lets us distinguish |
| 533 // cases like: | 534 // cases like: |
| 534 // | 535 // |
| 535 // dynamic d; | 536 // dynamic d; |
| 536 // d.someMethod(...); // the whole method call must be a dynamic send. | 537 // d.someMethod(...); // the whole method call must be a dynamic send. |
| 537 // | 538 // |
| 538 // ... from case like: | 539 // ... from case like: |
| 539 // | 540 // |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 | 604 |
| 604 @override | 605 @override |
| 605 void visitYieldStatement(YieldStatement node) { | 606 void visitYieldStatement(YieldStatement node) { |
| 606 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); | 607 _checkReturnOrYield(node.expression, node, yieldStar: node.star != null); |
| 607 node.visitChildren(this); | 608 node.visitChildren(this); |
| 608 } | 609 } |
| 609 | 610 |
| 610 @override | 611 @override |
| 611 void visitPropertyAccess(PropertyAccess node) { | 612 void visitPropertyAccess(PropertyAccess node) { |
| 612 var target = node.realTarget; | 613 var target = node.realTarget; |
| 613 if (rules.isDynamicTarget(target)) { | 614 if (rules.isDynamicTarget(target) && |
| 615 !_isObjectProperty(target, node.propertyName)) { |
| 614 _recordDynamicInvoke(node, target); | 616 _recordDynamicInvoke(node, target); |
| 615 } | 617 } |
| 616 node.visitChildren(this); | 618 node.visitChildren(this); |
| 617 } | 619 } |
| 618 | 620 |
| 619 @override | 621 @override |
| 620 void visitPrefixedIdentifier(PrefixedIdentifier node) { | 622 void visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 621 final target = node.prefix; | 623 final target = node.prefix; |
| 622 if (rules.isDynamicTarget(target)) { | 624 if (rules.isDynamicTarget(target) && |
| 625 !_isObjectProperty(target, node.identifier)) { |
| 623 _recordDynamicInvoke(node, target); | 626 _recordDynamicInvoke(node, target); |
| 624 } | 627 } |
| 625 node.visitChildren(this); | 628 node.visitChildren(this); |
| 626 } | 629 } |
| 627 | 630 |
| 628 @override | 631 @override |
| 629 void visitDefaultFormalParameter(DefaultFormalParameter node) { | 632 void visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 630 // Check that defaults have the proper subtype. | 633 // Check that defaults have the proper subtype. |
| 631 var parameter = node.parameter; | 634 var parameter = node.parameter; |
| 632 var parameterType = rules.elementType(parameter.element); | 635 var parameterType = rules.elementType(parameter.element); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 | 916 |
| 914 // Check the rhs type | 917 // Check the rhs type |
| 915 if (staticInfo is! CoercionInfo) { | 918 if (staticInfo is! CoercionInfo) { |
| 916 var paramType = paramTypes.first; | 919 var paramType = paramTypes.first; |
| 917 staticInfo = rules.checkAssignment(expr.rightHandSide, paramType); | 920 staticInfo = rules.checkAssignment(expr.rightHandSide, paramType); |
| 918 _recordMessage(staticInfo); | 921 _recordMessage(staticInfo); |
| 919 } | 922 } |
| 920 } | 923 } |
| 921 } | 924 } |
| 922 | 925 |
| 926 bool _isObjectGetter(Expression target, SimpleIdentifier id) { |
| 927 PropertyAccessorElement element = |
| 928 rules.provider.objectType.element.getGetter(id.name); |
| 929 return (element != null && !element.isStatic); |
| 930 } |
| 931 |
| 932 bool _isObjectMethod(Expression target, SimpleIdentifier id) { |
| 933 MethodElement element = |
| 934 rules.provider.objectType.element.getMethod(id.name); |
| 935 return (element != null && !element.isStatic); |
| 936 } |
| 937 |
| 938 bool _isObjectProperty(Expression target, SimpleIdentifier id) { |
| 939 return _isObjectGetter(target, id) || _isObjectMethod(target, id); |
| 940 } |
| 941 |
| 923 void _recordDynamicInvoke(AstNode node, AstNode target) { | 942 void _recordDynamicInvoke(AstNode node, AstNode target) { |
| 924 reporter.onError(new DynamicInvoke(rules, node).toAnalysisError()); | 943 reporter.onError(new DynamicInvoke(rules, node).toAnalysisError()); |
| 925 // TODO(jmesserly): we may eventually want to record if the whole operation | 944 // TODO(jmesserly): we may eventually want to record if the whole operation |
| 926 // (node) was dynamic, rather than the target, but this is an easier fit | 945 // (node) was dynamic, rather than the target, but this is an easier fit |
| 927 // with what we used to do. | 946 // with what we used to do. |
| 928 DynamicInvoke.set(target, true); | 947 DynamicInvoke.set(target, true); |
| 929 } | 948 } |
| 930 | 949 |
| 931 void _recordMessage(StaticInfo info) { | 950 void _recordMessage(StaticInfo info) { |
| 932 if (info == null) return; | 951 if (info == null) return; |
| 933 var error = info.toAnalysisError(); | 952 var error = info.toAnalysisError(); |
| 934 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; | 953 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; |
| 935 reporter.onError(error); | 954 reporter.onError(error); |
| 936 | 955 |
| 937 if (info is CoercionInfo) { | 956 if (info is CoercionInfo) { |
| 938 // TODO(jmesserly): if we're run again on the same AST, we'll produce the | 957 // TODO(jmesserly): if we're run again on the same AST, we'll produce the |
| 939 // same annotations. This should be harmless. This might go away once | 958 // same annotations. This should be harmless. This might go away once |
| 940 // CodeChecker is integrated better with analyzer, as it will know that | 959 // CodeChecker is integrated better with analyzer, as it will know that |
| 941 // checking has already been performed. | 960 // checking has already been performed. |
| 942 // assert(CoercionInfo.get(info.node) == null); | 961 // assert(CoercionInfo.get(info.node) == null); |
| 943 CoercionInfo.set(info.node, info); | 962 CoercionInfo.set(info.node, info); |
| 944 } | 963 } |
| 945 } | 964 } |
| 946 } | 965 } |
| OLD | NEW |