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 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
| 6 // refactored to fit into analyzer. | 6 // refactored to fit into analyzer. |
| 7 library analyzer.src.task.strong.checker; | 7 library analyzer.src.task.strong.checker; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 ? typeProvider.streamType | 338 ? typeProvider.streamType |
| 339 : typeProvider.iterableType; | 339 : typeProvider.iterableType; |
| 340 var iterableType = _getStaticType(node.iterable); | 340 var iterableType = _getStaticType(node.iterable); |
| 341 var elementType = | 341 var elementType = |
| 342 rules.mostSpecificTypeArgument(iterableType, sequenceInterface); | 342 rules.mostSpecificTypeArgument(iterableType, sequenceInterface); |
| 343 | 343 |
| 344 // If the sequence is not an Iterable (or Stream for await for) but is a | 344 // If the sequence is not an Iterable (or Stream for await for) but is a |
| 345 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then | 345 // supertype of it, do an implicit downcast to Iterable<dynamic>. Then |
| 346 // we'll do a separate cast of the dynamic element to the variable's type. | 346 // we'll do a separate cast of the dynamic element to the variable's type. |
| 347 if (elementType == null) { | 347 if (elementType == null) { |
| 348 var sequenceType = sequenceInterface.instantiate([DynamicTypeImpl.instan ce]); | 348 var sequenceType = |
| 349 sequenceInterface.instantiate([DynamicTypeImpl.instance]); | |
| 349 | 350 |
| 350 if (rules.isSubtypeOf(sequenceType, iterableType)) { | 351 if (rules.isSubtypeOf(sequenceType, iterableType)) { |
| 351 _recordMessage(DownCast.create( | 352 _recordMessage(DownCast.create( |
| 352 rules, node.iterable, iterableType, sequenceType)); | 353 rules, node.iterable, iterableType, sequenceType)); |
| 353 elementType = DynamicTypeImpl.instance; | 354 elementType = DynamicTypeImpl.instance; |
| 354 } | 355 } |
| 355 } | 356 } |
| 356 | 357 |
| 357 // If the sequence doesn't implement the interface at all, [ErrorVerifier] | 358 // If the sequence doesn't implement the interface at all, [ErrorVerifier] |
| 358 // will report the error, so ignore it here. | 359 // will report the error, so ignore it here. |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 } | 630 } |
| 630 | 631 |
| 631 // Check the rhs type | 632 // Check the rhs type |
| 632 if (staticInfo is! CoercionInfo) { | 633 if (staticInfo is! CoercionInfo) { |
| 633 var paramType = paramTypes.first; | 634 var paramType = paramTypes.first; |
| 634 _checkDowncast(expr.rightHandSide, paramType); | 635 _checkDowncast(expr.rightHandSide, paramType); |
| 635 } | 636 } |
| 636 } | 637 } |
| 637 } | 638 } |
| 638 | 639 |
| 640 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. | |
|
Bob Nystrom
2016/03/28 19:59:40
Are there changes to this, or did it just move? Is
Brian Wilkerson
2016/03/28 20:34:33
No, there are no changes. I was only expecting cha
| |
| 641 /// | |
| 642 /// If [from] is omitted, uses the static type of [expr]. | |
| 643 /// | |
| 644 /// If [expr] does not require a downcast because it is not related to [to] | |
| 645 /// or is already a subtype of it, does nothing. | |
| 646 void _checkDowncast(Expression expr, DartType to, {DartType from}) { | |
| 647 if (from == null) { | |
| 648 from = _getStaticType(expr); | |
| 649 } | |
| 650 | |
| 651 // We can use anything as void. | |
| 652 if (to.isVoid) return; | |
| 653 | |
| 654 // fromT <: toT, no coercion needed. | |
| 655 if (rules.isSubtypeOf(from, to)) return; | |
| 656 | |
| 657 // TODO(vsm): We can get rid of the second clause if we disallow | |
| 658 // all sideways casts - see TODO below. | |
| 659 // ------- | |
| 660 // Note: a function type is never assignable to a class per the Dart | |
| 661 // spec - even if it has a compatible call method. We disallow as | |
| 662 // well for consistency. | |
| 663 if ((from is FunctionType && rules.getCallMethodType(to) != null) || | |
| 664 (to is FunctionType && rules.getCallMethodType(from) != null)) { | |
| 665 return; | |
| 666 } | |
| 667 | |
| 668 // Downcast if toT <: fromT | |
| 669 if (rules.isSubtypeOf(to, from)) { | |
| 670 _recordMessage(DownCast.create(rules, expr, from, to)); | |
| 671 return; | |
| 672 } | |
| 673 | |
| 674 // TODO(vsm): Once we have generic methods, we should delete this | |
| 675 // workaround. These sideways casts are always ones we warn about | |
| 676 // - i.e., we think they are likely to fail at runtime. | |
| 677 // ------- | |
| 678 // Downcast if toT <===> fromT | |
| 679 // The intention here is to allow casts that are sideways in the restricted | |
| 680 // type system, but allowed in the regular dart type system, since these | |
| 681 // are likely to succeed. The canonical example is List<dynamic> and | |
| 682 // Iterable<T> for some concrete T (e.g. Object). These are unrelated | |
| 683 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. | |
| 684 if (from.isAssignableTo(to)) { | |
| 685 _recordMessage(DownCast.create(rules, expr, from, to)); | |
| 686 } | |
| 687 } | |
| 688 | |
| 639 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { | 689 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { |
| 640 if ((_isDynamicTarget(target) || field.staticElement == null) && | 690 if ((_isDynamicTarget(target) || field.staticElement == null) && |
| 641 !_isObjectProperty(target, field)) { | 691 !_isObjectProperty(target, field)) { |
| 642 _recordDynamicInvoke(node, target); | 692 _recordDynamicInvoke(node, target); |
| 643 } | 693 } |
| 644 node.visitChildren(this); | 694 node.visitChildren(this); |
| 645 } | 695 } |
| 646 | 696 |
| 647 void _checkReturnOrYield(Expression expression, AstNode node, | 697 void _checkReturnOrYield(Expression expression, AstNode node, |
| 648 {bool yieldStar: false}) { | 698 {bool yieldStar: false}) { |
| 649 var body = node.getAncestor((n) => n is FunctionBody); | 699 FunctionBody body = node.getAncestor((n) => n is FunctionBody); |
| 650 var type = _getExpectedReturnType(body, yieldStar: yieldStar); | 700 var type = _getExpectedReturnType(body, yieldStar: yieldStar); |
| 651 if (type == null) { | 701 if (type == null) { |
| 652 // We have a type mismatch: the async/async*/sync* modifier does | 702 // We have a type mismatch: the async/async*/sync* modifier does |
| 653 // not match the return or yield type. We should have already gotten an | 703 // not match the return or yield type. We should have already gotten an |
| 654 // analyzer error in this case. | 704 // analyzer error in this case. |
| 655 return; | 705 return; |
| 656 } | 706 } |
| 657 InterfaceType futureType = typeProvider.futureType; | 707 InterfaceType futureType = typeProvider.futureType; |
| 658 DartType actualType = expression?.staticType; | 708 DartType actualType = expression?.staticType; |
| 659 if (body.isAsynchronous && | 709 if (body.isAsynchronous && |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 680 op.type == TokenType.MINUS_MINUS) { | 730 op.type == TokenType.MINUS_MINUS) { |
| 681 if (_isDynamicTarget(node.operand)) { | 731 if (_isDynamicTarget(node.operand)) { |
| 682 _recordDynamicInvoke(node, node.operand); | 732 _recordDynamicInvoke(node, node.operand); |
| 683 } | 733 } |
| 684 // For ++ and --, even if it is not dynamic, we still need to check | 734 // For ++ and --, even if it is not dynamic, we still need to check |
| 685 // that the user defined method accepts an `int` as the RHS. | 735 // that the user defined method accepts an `int` as the RHS. |
| 686 // We assume Analyzer has done this already. | 736 // We assume Analyzer has done this already. |
| 687 } | 737 } |
| 688 } | 738 } |
| 689 | 739 |
| 690 /// Records a [DownCast] of [expr] from [from] to [to], if there is one. | |
| 691 /// | |
| 692 /// If [from] is omitted, uses the static type of [expr]. | |
| 693 /// | |
| 694 /// If [expr] does not require a downcast because it is not related to [to] | |
| 695 /// or is already a subtype of it, does nothing. | |
| 696 void _checkDowncast(Expression expr, DartType to, {DartType from}) { | |
| 697 if (from == null) { | |
| 698 from = _getStaticType(expr); | |
| 699 } | |
| 700 | |
| 701 // We can use anything as void. | |
| 702 if (to.isVoid) return; | |
| 703 | |
| 704 // fromT <: toT, no coercion needed. | |
| 705 if (rules.isSubtypeOf(from, to)) return; | |
| 706 | |
| 707 // TODO(vsm): We can get rid of the second clause if we disallow | |
| 708 // all sideways casts - see TODO below. | |
| 709 // ------- | |
| 710 // Note: a function type is never assignable to a class per the Dart | |
| 711 // spec - even if it has a compatible call method. We disallow as | |
| 712 // well for consistency. | |
| 713 if ((from is FunctionType && rules.getCallMethodType(to) != null) || | |
| 714 (to is FunctionType && rules.getCallMethodType(from) != null)) { | |
| 715 return; | |
| 716 } | |
| 717 | |
| 718 // Downcast if toT <: fromT | |
| 719 if (rules.isSubtypeOf(to, from)) { | |
| 720 _recordMessage(DownCast.create(rules, expr, from, to)); | |
| 721 return; | |
| 722 } | |
| 723 | |
| 724 // TODO(vsm): Once we have generic methods, we should delete this | |
| 725 // workaround. These sideways casts are always ones we warn about | |
| 726 // - i.e., we think they are likely to fail at runtime. | |
| 727 // ------- | |
| 728 // Downcast if toT <===> fromT | |
| 729 // The intention here is to allow casts that are sideways in the restricted | |
| 730 // type system, but allowed in the regular dart type system, since these | |
| 731 // are likely to succeed. The canonical example is List<dynamic> and | |
| 732 // Iterable<T> for some concrete T (e.g. Object). These are unrelated | |
| 733 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. | |
| 734 if (from.isAssignableTo(to)) { | |
| 735 _recordMessage(DownCast.create(rules, expr, from, to)); | |
| 736 } | |
| 737 } | |
| 738 | |
| 739 // Produce a coercion which coerces something of type fromT | 740 // Produce a coercion which coerces something of type fromT |
| 740 // to something of type toT. | 741 // to something of type toT. |
| 741 // Returns the error coercion if the types cannot be coerced | 742 // Returns the error coercion if the types cannot be coerced |
| 742 // according to our current criteria. | 743 // according to our current criteria. |
| 743 /// Gets the expected return type of the given function [body], either from | 744 /// Gets the expected return type of the given function [body], either from |
| 744 /// a normal return/yield, or from a yield*. | 745 /// a normal return/yield, or from a yield*. |
| 745 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { | 746 DartType _getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) { |
| 746 FunctionType functionType; | 747 FunctionType functionType; |
| 747 var parent = body.parent; | 748 var parent = body.parent; |
| 748 if (parent is Declaration) { | 749 if (parent is Declaration) { |
| 749 functionType = _elementType(parent.element); | 750 functionType = _elementType(parent.element); |
| 750 } else { | 751 } else { |
| 751 assert(parent is FunctionExpression); | 752 assert(parent is FunctionExpression); |
| 752 functionType = parent.staticType ?? DynamicTypeImpl.instance; | 753 functionType = |
| 754 (parent as FunctionExpression).staticType ?? DynamicTypeImpl.instance; | |
| 753 } | 755 } |
| 754 | 756 |
| 755 var type = functionType.returnType; | 757 var type = functionType.returnType; |
| 756 | 758 |
| 757 InterfaceType expectedType = null; | 759 InterfaceType expectedType = null; |
| 758 if (body.isAsynchronous) { | 760 if (body.isAsynchronous) { |
| 759 if (body.isGenerator) { | 761 if (body.isGenerator) { |
| 760 // Stream<T> -> T | 762 // Stream<T> -> T |
| 761 expectedType = typeProvider.streamType; | 763 expectedType = typeProvider.streamType; |
| 762 } else { | 764 } else { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 797 DartType t = expr.staticType ?? DynamicTypeImpl.instance; | 799 DartType t = expr.staticType ?? DynamicTypeImpl.instance; |
| 798 | 800 |
| 799 // Remove fuzzy arrow if possible. | 801 // Remove fuzzy arrow if possible. |
| 800 if (t is FunctionType && StaticInfo.isKnownFunction(expr)) { | 802 if (t is FunctionType && StaticInfo.isKnownFunction(expr)) { |
| 801 t = _removeFuzz(t); | 803 t = _removeFuzz(t); |
| 802 } | 804 } |
| 803 | 805 |
| 804 return t; | 806 return t; |
| 805 } | 807 } |
| 806 | 808 |
| 807 /// Remove "fuzzy arrow" in this function type. | |
| 808 /// | |
| 809 /// Normally we treat dynamically typed parameters as bottom for function | |
| 810 /// types. This allows type tests such as `if (f is SingleArgFunction)`. | |
| 811 /// It also requires a dynamic check on the parameter type to call these | |
| 812 /// functions. | |
| 813 /// | |
| 814 /// When we convert to a strict arrow, dynamically typed parameters become | |
| 815 /// top. This is safe to do for known functions, like top-level or local | |
| 816 /// functions and static methods. Those functions must already be essentially | |
| 817 /// treating dynamic as top. | |
| 818 /// | |
| 819 /// Only the outer-most arrow can be strict. Any others must be fuzzy, because | |
| 820 /// we don't know what function value will be passed there. | |
| 821 // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function | |
| 822 // type? That would allow us to implement this in the subtype relation. | |
| 823 // TODO(jmesserly): we'll need to factor this differently if we want to | |
| 824 // move CodeChecker's functionality into existing analyzer. Likely we can | |
| 825 // let the Expression have a strict arrow, then in places were we do | |
| 826 // inference, convert back to a fuzzy arrow. | |
| 827 FunctionType _removeFuzz(FunctionType t) { | |
| 828 bool foundFuzz = false; | |
| 829 List<ParameterElement> parameters = <ParameterElement>[]; | |
| 830 for (ParameterElement p in t.parameters) { | |
| 831 ParameterElement newP = _removeParameterFuzz(p); | |
| 832 parameters.add(newP); | |
| 833 if (p != newP) foundFuzz = true; | |
| 834 } | |
| 835 if (!foundFuzz) { | |
| 836 return t; | |
| 837 } | |
| 838 | |
| 839 FunctionElementImpl function = new FunctionElementImpl("", -1); | |
| 840 function.synthetic = true; | |
| 841 function.returnType = t.returnType; | |
| 842 function.shareTypeParameters(t.typeFormals); | |
| 843 function.shareParameters(parameters); | |
| 844 return function.type = new FunctionTypeImpl(function); | |
| 845 } | |
| 846 | |
| 847 /// Removes fuzzy arrow, see [_removeFuzz]. | |
| 848 ParameterElement _removeParameterFuzz(ParameterElement p) { | |
| 849 if (p.type.isDynamic) { | |
| 850 return new ParameterElementImpl.synthetic( | |
| 851 p.name, typeProvider.objectType, p.parameterKind); | |
| 852 } | |
| 853 return p; | |
| 854 } | |
| 855 | |
| 856 /// Given an expression, return its type assuming it is | 809 /// Given an expression, return its type assuming it is |
| 857 /// in the caller position of a call (that is, accounting | 810 /// in the caller position of a call (that is, accounting |
| 858 /// for the possibility of a call method). Returns null | 811 /// for the possibility of a call method). Returns null |
| 859 /// if expression is not statically callable. | 812 /// if expression is not statically callable. |
| 860 FunctionType _getTypeAsCaller(Expression node) { | 813 FunctionType _getTypeAsCaller(Expression node) { |
| 861 DartType t = node.staticType; | 814 DartType t = node.staticType; |
| 862 if (node is SimpleIdentifier) { | 815 if (node is SimpleIdentifier) { |
| 863 Expression parent = node.parent; | 816 Expression parent = node.parent; |
| 864 if (parent is MethodInvocation) { | 817 if (parent is MethodInvocation) { |
| 865 t = parent.staticInvokeType; | 818 t = parent.staticInvokeType; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 948 if (info is CoercionInfo) { | 901 if (info is CoercionInfo) { |
| 949 // TODO(jmesserly): if we're run again on the same AST, we'll produce the | 902 // TODO(jmesserly): if we're run again on the same AST, we'll produce the |
| 950 // same annotations. This should be harmless. This might go away once | 903 // same annotations. This should be harmless. This might go away once |
| 951 // CodeChecker is integrated better with analyzer, as it will know that | 904 // CodeChecker is integrated better with analyzer, as it will know that |
| 952 // checking has already been performed. | 905 // checking has already been performed. |
| 953 // assert(CoercionInfo.get(info.node) == null); | 906 // assert(CoercionInfo.get(info.node) == null); |
| 954 CoercionInfo.set(info.node, info); | 907 CoercionInfo.set(info.node, info); |
| 955 } | 908 } |
| 956 } | 909 } |
| 957 | 910 |
| 911 /// Remove "fuzzy arrow" in this function type. | |
| 912 /// | |
| 913 /// Normally we treat dynamically typed parameters as bottom for function | |
| 914 /// types. This allows type tests such as `if (f is SingleArgFunction)`. | |
| 915 /// It also requires a dynamic check on the parameter type to call these | |
| 916 /// functions. | |
| 917 /// | |
| 918 /// When we convert to a strict arrow, dynamically typed parameters become | |
| 919 /// top. This is safe to do for known functions, like top-level or local | |
| 920 /// functions and static methods. Those functions must already be essentially | |
| 921 /// treating dynamic as top. | |
| 922 /// | |
| 923 /// Only the outer-most arrow can be strict. Any others must be fuzzy, because | |
| 924 /// we don't know what function value will be passed there. | |
| 925 // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function | |
| 926 // type? That would allow us to implement this in the subtype relation. | |
| 927 // TODO(jmesserly): we'll need to factor this differently if we want to | |
| 928 // move CodeChecker's functionality into existing analyzer. Likely we can | |
| 929 // let the Expression have a strict arrow, then in places were we do | |
| 930 // inference, convert back to a fuzzy arrow. | |
| 931 FunctionType _removeFuzz(FunctionType t) { | |
| 932 bool foundFuzz = false; | |
| 933 List<ParameterElement> parameters = <ParameterElement>[]; | |
| 934 for (ParameterElement p in t.parameters) { | |
| 935 ParameterElement newP = _removeParameterFuzz(p); | |
| 936 parameters.add(newP); | |
| 937 if (p != newP) foundFuzz = true; | |
| 938 } | |
| 939 if (!foundFuzz) { | |
| 940 return t; | |
| 941 } | |
| 942 | |
| 943 FunctionElementImpl function = new FunctionElementImpl("", -1); | |
| 944 function.synthetic = true; | |
| 945 function.returnType = t.returnType; | |
| 946 function.shareTypeParameters(t.typeFormals); | |
| 947 function.shareParameters(parameters); | |
| 948 return function.type = new FunctionTypeImpl(function); | |
| 949 } | |
| 950 | |
| 951 /// Removes fuzzy arrow, see [_removeFuzz]. | |
| 952 ParameterElement _removeParameterFuzz(ParameterElement p) { | |
| 953 if (p.type.isDynamic) { | |
| 954 return new ParameterElementImpl.synthetic( | |
| 955 p.name, typeProvider.objectType, p.parameterKind); | |
| 956 } | |
| 957 return p; | |
| 958 } | |
| 959 | |
| 958 DartType _specializedBinaryReturnType( | 960 DartType _specializedBinaryReturnType( |
| 959 TokenType op, DartType t1, DartType t2, DartType normalReturnType) { | 961 TokenType op, DartType t1, DartType t2, DartType normalReturnType) { |
| 960 // This special cases binary return types as per 16.26 and 16.27 of the | 962 // This special cases binary return types as per 16.26 and 16.27 of the |
| 961 // Dart language spec. | 963 // Dart language spec. |
| 962 switch (op) { | 964 switch (op) { |
| 963 case TokenType.PLUS: | 965 case TokenType.PLUS: |
| 964 case TokenType.MINUS: | 966 case TokenType.MINUS: |
| 965 case TokenType.STAR: | 967 case TokenType.STAR: |
| 966 case TokenType.TILDE_SLASH: | 968 case TokenType.TILDE_SLASH: |
| 967 case TokenType.PERCENT: | 969 case TokenType.PERCENT: |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1051 } | 1053 } |
| 1052 | 1054 |
| 1053 /// Check that individual methods and fields in [subType] correctly override | 1055 /// Check that individual methods and fields in [subType] correctly override |
| 1054 /// the declarations in [baseType]. | 1056 /// the declarations in [baseType]. |
| 1055 /// | 1057 /// |
| 1056 /// The [errorLocation] node indicates where errors are reported, see | 1058 /// The [errorLocation] node indicates where errors are reported, see |
| 1057 /// [_checkSingleOverride] for more details. | 1059 /// [_checkSingleOverride] for more details. |
| 1058 _checkIndividualOverridesFromClass(ClassDeclaration node, | 1060 _checkIndividualOverridesFromClass(ClassDeclaration node, |
| 1059 InterfaceType baseType, Set<String> seen, bool isSubclass) { | 1061 InterfaceType baseType, Set<String> seen, bool isSubclass) { |
| 1060 for (var member in node.members) { | 1062 for (var member in node.members) { |
| 1061 if (member is ConstructorDeclaration) continue; | |
| 1062 if (member is FieldDeclaration) { | 1063 if (member is FieldDeclaration) { |
| 1063 if (member.isStatic) continue; | 1064 if (member.isStatic) continue; |
| 1064 for (var variable in member.fields.variables) { | 1065 for (var variable in member.fields.variables) { |
| 1065 var element = variable.element as PropertyInducingElement; | 1066 var element = variable.element as PropertyInducingElement; |
| 1066 var name = element.name; | 1067 var name = element.name; |
| 1067 if (seen.contains(name)) continue; | 1068 if (seen.contains(name)) continue; |
| 1068 var getter = element.getter; | 1069 var getter = element.getter; |
| 1069 var setter = element.setter; | 1070 var setter = element.setter; |
| 1070 bool found = _checkSingleOverride( | 1071 bool found = _checkSingleOverride( |
| 1071 getter, baseType, variable, member, isSubclass); | 1072 getter, baseType, variable.name, member, isSubclass); |
| 1072 if (!variable.isFinal && | 1073 if (!variable.isFinal && |
| 1073 !variable.isConst && | 1074 !variable.isConst && |
| 1074 _checkSingleOverride( | 1075 _checkSingleOverride( |
| 1075 setter, baseType, variable, member, isSubclass)) { | 1076 setter, baseType, variable.name, member, isSubclass)) { |
| 1076 found = true; | 1077 found = true; |
| 1077 } | 1078 } |
| 1078 if (found) seen.add(name); | 1079 if (found) seen.add(name); |
| 1079 } | 1080 } |
| 1080 } else { | 1081 } else if (member is MethodDeclaration) { |
| 1081 if ((member as MethodDeclaration).isStatic) continue; | 1082 if (member.isStatic) continue; |
| 1082 var method = (member as MethodDeclaration).element; | 1083 var method = member.element; |
| 1083 if (seen.contains(method.name)) continue; | 1084 if (seen.contains(method.name)) continue; |
| 1084 if (_checkSingleOverride( | 1085 if (_checkSingleOverride( |
| 1085 method, baseType, member, member, isSubclass)) { | 1086 method, baseType, member.name, member, isSubclass)) { |
| 1086 seen.add(method.name); | 1087 seen.add(method.name); |
| 1087 } | 1088 } |
| 1088 } | 1089 } |
|
Bob Nystrom
2016/03/28 19:59:40
Maybe leave a comment or assert that the only rema
Brian Wilkerson
2016/03/28 20:34:33
I'll do that.
| |
| 1089 } | 1090 } |
| 1090 } | 1091 } |
| 1091 | 1092 |
| 1092 /// Check that individual methods and fields in [subType] correctly override | 1093 /// Check that individual methods and fields in [subType] correctly override |
| 1093 /// the declarations in [baseType]. | 1094 /// the declarations in [baseType]. |
| 1094 /// | 1095 /// |
| 1095 /// The [errorLocation] node indicates where errors are reported, see | 1096 /// The [errorLocation] node indicates where errors are reported, see |
| 1096 /// [_checkSingleOverride] for more details. | 1097 /// [_checkSingleOverride] for more details. |
| 1097 /// | 1098 /// |
| 1098 /// The set [seen] is used to avoid reporting overrides more than once. It | 1099 /// The set [seen] is used to avoid reporting overrides more than once. It |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1299 } while (!current.isObject && !visited.contains(current)); | 1300 } while (!current.isObject && !visited.contains(current)); |
| 1300 } | 1301 } |
| 1301 | 1302 |
| 1302 void _recordMessage(StaticInfo info) { | 1303 void _recordMessage(StaticInfo info) { |
| 1303 if (info == null) return; | 1304 if (info == null) return; |
| 1304 var error = info.toAnalysisError(); | 1305 var error = info.toAnalysisError(); |
| 1305 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; | 1306 if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true; |
| 1306 _reporter.onError(error); | 1307 _reporter.onError(error); |
| 1307 } | 1308 } |
| 1308 } | 1309 } |
| OLD | NEW |