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 |