Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: pkg/analyzer/lib/src/task/strong/checker.dart

Issue 2988673003: fix override checking of mixins (Closed)
Patch Set: update status Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/strong/checker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698