| 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 'dart:collection'; | 9 import 'dart:collection'; |
| 10 import 'package:analyzer/analyzer.dart'; | 10 import 'package:analyzer/analyzer.dart'; |
| (...skipping 1647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1658 element.mixins.forEach(visitTypeAndSupertypes); | 1658 element.mixins.forEach(visitTypeAndSupertypes); |
| 1659 element.interfaces.forEach(visitTypeAndSupertypes); | 1659 element.interfaces.forEach(visitTypeAndSupertypes); |
| 1660 } | 1660 } |
| 1661 } | 1661 } |
| 1662 | 1662 |
| 1663 visitTypeAndSupertypes(type); | 1663 visitTypeAndSupertypes(type); |
| 1664 | 1664 |
| 1665 return genericSupertypes; | 1665 return genericSupertypes; |
| 1666 } | 1666 } |
| 1667 | 1667 |
| 1668 /// Checks that members on this class correctly override all reachable | 1668 /// Checks that most-derived concrete members on this class correctly override |
| 1669 /// interfaces. | 1669 /// all reachable interfaces, and reports errors if all interfaces are not |
| 1670 /// correctly implemented. |
| 1671 /// |
| 1672 /// This checks the soundness property: for all interfaces implemented by this |
| 1673 /// class (including inherited interfaces), we ensure that calls through that |
| 1674 /// interface will be sound. |
| 1670 void _checkAllInterfaceOverrides(Declaration node, ClassElement element) { | 1675 void _checkAllInterfaceOverrides(Declaration node, ClassElement element) { |
| 1671 var interfaces = _collectInterfacesToCheck(element.type); | 1676 var interfaces = _collectInterfacesToCheck(element.type); |
| 1672 var visitedClasses = new Set<InterfaceType>(); | 1677 var visitedClasses = new Set<InterfaceType>(); |
| 1678 var visitedMembers = new HashSet<String>(); |
| 1673 | 1679 |
| 1674 // Visit all members on `type` (including inherited) and report errors if | 1680 // Checks all most-derived concrete members on this `type`. We skip over |
| 1675 // all `interfaces` are not correctly overridden. | 1681 // members that are already `visitedMembers`, because they were overridden |
| 1682 // and we've already checked that member. |
| 1676 // | 1683 // |
| 1677 // Generally we only need to check the most derived concrete member, and | 1684 // Because of that, it is important we visit types in the order that they |
| 1678 // we record members that have been seen already in `seen`. However we do | 1685 // will override members. |
| 1679 // report errors for every mixin member (unless it is overridden) by | 1686 void checkType(InterfaceType type, AstNode location) { |
| 1680 // the class itself. | 1687 // Skip `Object` because we don't need to check those members here. |
| 1681 // | 1688 // (because `Object` is the root of everything, it will be checked in |
| 1682 // TODO(jmesserly): what should mixins be doing? This behavior does not | 1689 // _checkSuperOverrides for all classes). |
| 1683 // seem correct, but it is preserved for backwards compatibility. | |
| 1684 void checkType(InterfaceType type, Set<String> seen, AstNode location) { | |
| 1685 if (type == null || type.isObject || !visitedClasses.add(type)) return; | 1690 if (type == null || type.isObject || !visitedClasses.add(type)) return; |
| 1686 | 1691 |
| 1687 // Check `member` against all `interfaces`. | 1692 // Check `member` against all `interfaces`. |
| 1688 void checkOverride(ExecutableElement member, [AstNode loc]) { | 1693 void checkOverride(ExecutableElement member, [AstNode loc]) { |
| 1689 if (!seen.add(member.name)) return; | 1694 if (!visitedMembers.add(member.name)) return; |
| 1690 for (var interface in interfaces) { | 1695 for (var interface in interfaces) { |
| 1691 if (_checkMemberOverride(member, interface, loc ?? location) == | 1696 if (_checkMemberOverride(member, interface, loc ?? location) == |
| 1692 false) { | 1697 false) { |
| 1693 // Only report one error per member for interfaces. | 1698 // Only report one error per member for interfaces. |
| 1694 // TODO(jmesserly): this is for backwards compatibility. Remove it? | 1699 // TODO(jmesserly): this is for backwards compatibility. Remove it? |
| 1695 break; | 1700 break; |
| 1696 } | 1701 } |
| 1697 } | 1702 } |
| 1698 } | 1703 } |
| 1699 | 1704 |
| 1705 // When we're checking the class declaration node we started from, we |
| 1706 // can use a more precise error location for reporting override errors. |
| 1707 // |
| 1708 // Otherwise, we'll use the `extends` or `with` clause. |
| 1709 var isRootClass = identical(location, node); |
| 1710 |
| 1700 // Check direct overrides on the class. | 1711 // Check direct overrides on the class. |
| 1701 var isRootClass = identical(location, node); | |
| 1702 if (isRootClass) { | 1712 if (isRootClass) { |
| 1703 _checkClassMembers(node, checkOverride); | 1713 _checkClassMembers(node, checkOverride); |
| 1704 } else { | 1714 } else { |
| 1705 _checkTypeMembers(type, checkOverride); | 1715 _checkTypeMembers(type, checkOverride); |
| 1706 } | 1716 } |
| 1707 | 1717 |
| 1708 // Check mixin members against interfaces. | 1718 // Check mixin members against interfaces. |
| 1709 // | 1719 // |
| 1710 // We want to check each mixin application class separately, so we report | 1720 // We visit mixins in reverse order to reflect how they override |
| 1711 // errors for any invalid overrides, even if multiple mixins have a member | 1721 // eachother. |
| 1712 // of the same name. | 1722 for (int i = type.mixins.length - 1; i >= 0; i--) { |
| 1713 for (int i = 0; i < type.mixins.length; i++) { | 1723 checkType(type.mixins[i], |
| 1714 checkType(type.mixins[i], new Set.from(seen), | |
| 1715 isRootClass ? _withClause(node).mixinTypes[i] : location); | 1724 isRootClass ? _withClause(node).mixinTypes[i] : location); |
| 1716 } | 1725 } |
| 1717 | 1726 |
| 1718 // Check members on the superclass. | 1727 // Check members on the superclass. |
| 1719 checkType(type.superclass, seen, | 1728 checkType(type.superclass, |
| 1720 isRootClass ? _extendsErrorLocation(node) : location); | 1729 isRootClass ? _extendsErrorLocation(node) : location); |
| 1721 } | 1730 } |
| 1722 | 1731 |
| 1723 checkType(element.type, new Set(), node); | 1732 checkType(element.type, node); |
| 1724 } | 1733 } |
| 1725 | 1734 |
| 1726 /// Gets the set of all interfaces on [type] that should be checked to see | 1735 /// Gets the set of all interfaces on [type] that should be checked to see |
| 1727 /// if type's members are overriding them correctly. | 1736 /// if type's members are overriding them correctly. |
| 1728 /// | 1737 /// |
| 1729 /// In particular, we need to check these overrides for the definitions in | 1738 /// In particular, we need to check these overrides for the definitions in |
| 1730 /// the class itself and each its superclasses (and mixins). | 1739 /// the class itself and each its superclasses (and mixins). |
| 1731 /// If a superclass (or mixin) is concrete, then we can skip its transitive | 1740 /// If a superclass (or mixin) is concrete, then we can skip its transitive |
| 1732 /// interfaces, but if it is abstract we must check them. For example, in: | 1741 /// interfaces, but if it is abstract we must check them. For example, in: |
| 1733 /// | 1742 /// |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1995 } | 2004 } |
| 1996 | 2005 |
| 1997 /// If node is a [ClassDeclaration] returns its members, otherwise if node is | 2006 /// If node is a [ClassDeclaration] returns its members, otherwise if node is |
| 1998 /// a [ClassTypeAlias] this returns an empty list. | 2007 /// a [ClassTypeAlias] this returns an empty list. |
| 1999 WithClause _withClause(Declaration node) { | 2008 WithClause _withClause(Declaration node) { |
| 2000 return node is ClassDeclaration | 2009 return node is ClassDeclaration |
| 2001 ? node.withClause | 2010 ? node.withClause |
| 2002 : (node as ClassTypeAlias).withClause; | 2011 : (node as ClassTypeAlias).withClause; |
| 2003 } | 2012 } |
| 2004 } | 2013 } |
| OLD | NEW |