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 1388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1399 | 1399 |
1400 // For members of the superclass, we may need to add checks because this | 1400 // For members of the superclass, we may need to add checks because this |
1401 // class adds a new unsafe interface. Collect those checks. | 1401 // class adds a new unsafe interface. Collect those checks. |
1402 checks = _findSuperclassCovariantChecks( | 1402 checks = _findSuperclassCovariantChecks( |
1403 element, allCovariant, seenConcreteMembers); | 1403 element, allCovariant, seenConcreteMembers); |
1404 // Store the checks on the class declaration, it will need to ensure the | 1404 // Store the checks on the class declaration, it will need to ensure the |
1405 // inherited members are appropriately guarded to ensure soundness. | 1405 // inherited members are appropriately guarded to ensure soundness. |
1406 setSuperclassCovariantParameters(node, checks); | 1406 setSuperclassCovariantParameters(node, checks); |
1407 } | 1407 } |
1408 | 1408 |
1409 /// For each member of this class and non-overridden inherited member, we | 1409 /// For each member of this class and non-overridden inherited member, we |
Jennifer Messerly
2017/07/27 21:07:58
fyi: this function is also doing a "concrete membe
| |
1410 /// check to see if any generic super interface permits an unsound call to the | 1410 /// check to see if any generic super interface permits an unsound call to the |
1411 /// concrete member. For example: | 1411 /// concrete member. For example: |
1412 /// | 1412 /// |
1413 /// We must check non-overridden inherited members because this class could | 1413 /// We must check non-overridden inherited members because this class could |
1414 /// contain a new interface that permits unsound access to that member. In | 1414 /// contain a new interface that permits unsound access to that member. In |
1415 /// those cases, the class is expected to insert stub that checks the type | 1415 /// those cases, the class is expected to insert stub that checks the type |
1416 /// before calling `super`. For example: | 1416 /// before calling `super`. For example: |
1417 /// | 1417 /// |
1418 /// class C<T> { | 1418 /// class C<T> { |
1419 /// add(T t) {} | 1419 /// add(T t) {} |
(...skipping 20 matching lines...) Expand all Loading... | |
1440 var oldCovariant = _findAllGenericInterfaces(type); | 1440 var oldCovariant = _findAllGenericInterfaces(type); |
1441 var newCovariant = allCovariant.difference(oldCovariant); | 1441 var newCovariant = allCovariant.difference(oldCovariant); |
1442 if (newCovariant.isEmpty) return; | 1442 if (newCovariant.isEmpty) return; |
1443 | 1443 |
1444 void visitSuper(InterfaceType type) { | 1444 void visitSuper(InterfaceType type) { |
1445 var element = type.element; | 1445 var element = type.element; |
1446 if (visited.add(element)) { | 1446 if (visited.add(element)) { |
1447 var members = _getConcreteMembers(type, seenConcreteMembers); | 1447 var members = _getConcreteMembers(type, seenConcreteMembers); |
1448 _findCovariantChecks(members, newCovariant, superChecks); | 1448 _findCovariantChecks(members, newCovariant, superChecks); |
1449 _findCovariantChecks(members, oldCovariant, existingChecks); | 1449 _findCovariantChecks(members, oldCovariant, existingChecks); |
1450 element.mixins.reversed.forEach(visitSuper); | 1450 element.mixins.reversed.forEach(visitSuper); |
Jennifer Messerly
2017/07/27 21:07:58
this could be problematic
| |
1451 var s = element.supertype; | 1451 var s = element.supertype; |
1452 if (s != null) visitSuper(s); | 1452 if (s != null) visitSuper(s); |
1453 } | 1453 } |
1454 } | 1454 } |
1455 | 1455 |
1456 visitSuper(type); | 1456 visitSuper(type); |
1457 } | 1457 } |
1458 | 1458 |
1459 element.mixins.reversed.forEach(visitImmediateSuper); | 1459 element.mixins.reversed.forEach(visitImmediateSuper); |
1460 var s = element.supertype; | 1460 var s = element.supertype; |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1630 var interfaces = _collectInterfacesToCheck(element.type); | 1630 var interfaces = _collectInterfacesToCheck(element.type); |
1631 var visitedClasses = new Set<InterfaceType>(); | 1631 var visitedClasses = new Set<InterfaceType>(); |
1632 var visitedMembers = new HashSet<String>(); | 1632 var visitedMembers = new HashSet<String>(); |
1633 | 1633 |
1634 // Checks all most-derived concrete members on this `type`. We skip over | 1634 // Checks all most-derived concrete members on this `type`. We skip over |
1635 // members that are already `visitedMembers`, because they were overridden | 1635 // members that are already `visitedMembers`, because they were overridden |
1636 // and we've already checked that member. | 1636 // and we've already checked that member. |
1637 // | 1637 // |
1638 // Because of that, it is important we visit types in the order that they | 1638 // Because of that, it is important we visit types in the order that they |
1639 // will override members. | 1639 // will override members. |
1640 void checkType(InterfaceType type, AstNode location) { | 1640 // If checkingMixin is true, then we are checking [type] in a mixin position |
1641 // and hence should consider its own mixins and superclass as abstract. | |
1642 void checkType(InterfaceType type, AstNode location, | |
1643 {bool checkingMixin: false}) { | |
1641 // Skip `Object` because we don't need to check those members here. | 1644 // Skip `Object` because we don't need to check those members here. |
1642 // (because `Object` is the root of everything, it will be checked in | 1645 // (because `Object` is the root of everything, it will be checked in |
1643 // _checkSuperOverrides for all classes). | 1646 // _checkSuperOverrides for all classes). |
1644 if (type == null || type.isObject || !visitedClasses.add(type)) return; | 1647 if (type == null || type.isObject || !visitedClasses.add(type)) return; |
1645 | 1648 |
1646 // Check `member` against all `interfaces`. | 1649 // Check `member` against all `interfaces`. |
1647 void checkOverride(ExecutableElement member, [AstNode loc]) { | 1650 void checkOverride(ExecutableElement member, [AstNode loc]) { |
1648 if (!visitedMembers.add(member.name)) return; | 1651 if (!visitedMembers.add(member.name)) return; |
1649 for (var interface in interfaces) { | 1652 for (var interface in interfaces) { |
1650 if (_checkMemberOverride(member, interface, loc ?? location) == | 1653 if (_checkMemberOverride(member, interface, loc ?? location) == |
(...skipping 11 matching lines...) Expand all Loading... | |
1662 // Otherwise, we'll use the `extends` or `with` clause. | 1665 // Otherwise, we'll use the `extends` or `with` clause. |
1663 var isRootClass = identical(location, node); | 1666 var isRootClass = identical(location, node); |
1664 | 1667 |
1665 // Check direct overrides on the class. | 1668 // Check direct overrides on the class. |
1666 if (isRootClass) { | 1669 if (isRootClass) { |
1667 _checkClassMembers(node, checkOverride); | 1670 _checkClassMembers(node, checkOverride); |
1668 } else { | 1671 } else { |
1669 _checkTypeMembers(type, checkOverride); | 1672 _checkTypeMembers(type, checkOverride); |
1670 } | 1673 } |
1671 | 1674 |
1672 // Check mixin members against interfaces. | 1675 // If we are currently checking a mixin, then its own mixins and |
1673 // | 1676 // superclass are abstract, and we should not check their members. |
1674 // We visit mixins in reverse order to reflect how they override | 1677 // This should only happen when super mixins is enabled, and we |
1675 // eachother. | 1678 // don't do proper checking for super mixins (we don't check that |
1676 for (int i = type.mixins.length - 1; i >= 0; i--) { | 1679 // the contract implied by the mixin declaration is satisfied by |
1677 checkType(type.mixins[i], | 1680 // the mixin use), but this prevents us from erroneously |
1678 isRootClass ? _withClause(node).mixinTypes[i] : location); | 1681 // rejecting some super mixin patterns. |
1682 // If this is a mixin application (class A = Object with B) | |
1683 // however, then we do still need to treat the mixin as concrete. | |
1684 if (!checkingMixin || type.element.isMixinApplication) { | |
1685 // Check mixin members against interfaces. | |
1686 // | |
1687 // We visit mixins in reverse order to reflect how they override | |
1688 // eachother. | |
1689 for (int i = type.mixins.length - 1; i >= 0; i--) { | |
1690 checkType(type.mixins[i], | |
1691 isRootClass ? _withClause(node).mixinTypes[i] : location, | |
1692 checkingMixin: true); | |
1693 } | |
1694 | |
1695 // Check members on the superclass. | |
1696 checkType(type.superclass, | |
1697 isRootClass ? _extendsErrorLocation(node) : location, | |
1698 checkingMixin: checkingMixin); | |
1679 } | 1699 } |
1680 | |
1681 // Check members on the superclass. | |
1682 checkType(type.superclass, | |
1683 isRootClass ? _extendsErrorLocation(node) : location); | |
1684 } | 1700 } |
1685 | 1701 |
1686 checkType(element.type, node); | 1702 checkType(element.type, node); |
1687 } | 1703 } |
1688 | 1704 |
1689 /// Gets the set of all interfaces on [type] that should be checked to see | 1705 /// Gets the set of all interfaces on [type] that should be checked to see |
1690 /// if type's members are overriding them correctly. | 1706 /// if type's members are overriding them correctly. |
1691 /// | 1707 /// |
1692 /// In particular, we need to check these overrides for the definitions in | 1708 /// In particular, we need to check these overrides for the definitions in |
1693 /// the class itself and each its superclasses (and mixins). | 1709 /// the class itself and each its superclasses (and mixins). |
(...skipping 23 matching lines...) Expand all Loading... | |
1717 // Check all interfaces reachable from the `implements` clause in the | 1733 // Check all interfaces reachable from the `implements` clause in the |
1718 // current class against definitions here and in superclasses. | 1734 // current class against definitions here and in superclasses. |
1719 type.interfaces.forEach(collectInterfaces); | 1735 type.interfaces.forEach(collectInterfaces); |
1720 | 1736 |
1721 // Also collect interfaces from any abstract mixins or superclasses. | 1737 // Also collect interfaces from any abstract mixins or superclasses. |
1722 // | 1738 // |
1723 // For a concrete mixin/superclass, we'll check that we override the | 1739 // For a concrete mixin/superclass, we'll check that we override the |
1724 // concrete members in _checkSuperOverrides and | 1740 // concrete members in _checkSuperOverrides and |
1725 // _checkMixinApplicationOverrides. But for abstract classes, we need to | 1741 // _checkMixinApplicationOverrides. But for abstract classes, we need to |
1726 // consider any abstract members it got from its interfaces. | 1742 // consider any abstract members it got from its interfaces. |
1727 for (var s in _getSuperclasses(type, (t) => t.element.isAbstract)) { | 1743 for (var s in _getSuperclasses(type, (t) => t.element.isAbstract)) { |
Jennifer Messerly
2017/07/27 21:07:58
based on comments below, this call site may need t
| |
1728 s.interfaces.forEach(collectInterfaces); | 1744 s.interfaces.forEach(collectInterfaces); |
1729 } | 1745 } |
1730 return interfaces; | 1746 return interfaces; |
1731 } | 1747 } |
1732 | 1748 |
1733 /// Visits each member on the class [node] and calls [checkMember] with the | 1749 /// Visits each member on the class [node] and calls [checkMember] with the |
1734 /// corresponding instance element and AST node (for error reporting). | 1750 /// corresponding instance element and AST node (for error reporting). |
1735 /// | 1751 /// |
1736 /// See also [_checkTypeMembers], which is used when the class AST node is not | 1752 /// See also [_checkTypeMembers], which is used when the class AST node is not |
1737 /// available. | 1753 /// available. |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1902 /// class Grandparent { | 1918 /// class Grandparent { |
1903 /// m(A a) {} | 1919 /// m(A a) {} |
1904 /// } | 1920 /// } |
1905 /// class Parent extends Grandparent { | 1921 /// class Parent extends Grandparent { |
1906 /// m(A a) {} | 1922 /// m(A a) {} |
1907 /// } | 1923 /// } |
1908 /// class Test extends Parent { | 1924 /// class Test extends Parent { |
1909 /// m(B a) {} // invalid override | 1925 /// m(B a) {} // invalid override |
1910 /// } | 1926 /// } |
1911 void _checkSuperOverrides(Declaration node, ClassElement element) { | 1927 void _checkSuperOverrides(Declaration node, ClassElement element) { |
1912 var superclasses = _getSuperclasses(element.type); | 1928 var superclasses = _getSuperclasses(element.type); |
Jennifer Messerly
2017/07/27 21:07:58
this set of concrete superclasses also contains mi
| |
1913 _checkClassMembers(node, (member, loc) { | 1929 _checkClassMembers(node, (member, loc) { |
1914 for (var s in superclasses) { | 1930 for (var s in superclasses) { |
1915 if (_checkConcreteMemberOverride(member, s, loc)) break; | 1931 if (_checkConcreteMemberOverride(member, s, loc)) break; |
Jennifer Messerly
2017/07/27 21:07:58
in particular, we'll break out of the loop once we
| |
1916 } | 1932 } |
1917 }); | 1933 }); |
1918 } | 1934 } |
1919 | 1935 |
1920 /// Collects all superclasses of [type], including any mixin application | 1936 /// Collects all superclasses of [type], including any mixin application |
1921 /// classes. | 1937 /// classes. |
1922 /// | 1938 /// |
1923 /// The search can be pruned by passing a [visitSuperclasses] function and | 1939 /// The search can be pruned by passing a [visitSuperclasses] function and |
1924 /// having it return `false` for types that should not be further explored. | 1940 /// having it return `false` for types that should not be further explored. |
1925 Iterable<InterfaceType> _getSuperclasses(InterfaceType type, | 1941 Iterable<InterfaceType> _getSuperclasses(InterfaceType type, |
1926 [bool visitSuperclasses(InterfaceType t)]) { | 1942 [bool visitSuperclasses(InterfaceType t)]) { |
1927 var superclasses = new Set<InterfaceType>(); | 1943 var superclasses = new Set<InterfaceType>(); |
1928 visit(InterfaceType t) { | 1944 visit(InterfaceType t) { |
1929 if ((visitSuperclasses == null || visitSuperclasses(t)) && | 1945 if ((visitSuperclasses == null || visitSuperclasses(t)) && |
1930 superclasses.add(t)) { | 1946 superclasses.add(t)) { |
1931 t.mixins.reversed.forEach(visit); | 1947 t.mixins.reversed.forEach(visit); |
Jennifer Messerly
2017/07/27 21:07:58
this may be the problematic location
| |
1932 var s = t.superclass; | 1948 var s = t.superclass; |
1933 if (s != null && !s.isObject) visit(s); | 1949 if (s != null && !s.isObject) visit(s); |
1934 } | 1950 } |
1935 } | 1951 } |
1936 | 1952 |
1937 type.mixins.reversed.forEach(visit); | 1953 type.mixins.reversed.forEach(visit); |
1938 var s = type.superclass; | 1954 var s = type.superclass; |
1939 if (s != null && !s.isObject) visit(s); | 1955 if (s != null && !s.isObject) visit(s); |
1940 | 1956 |
1941 // Make sure we record Object last, and not when we visit our mixins. | 1957 // Make sure we record Object last, and not when we visit our mixins. |
(...skipping 16 matching lines...) Expand all Loading... | |
1958 } | 1974 } |
1959 | 1975 |
1960 /// If node is a [ClassDeclaration] returns its members, otherwise if node is | 1976 /// If node is a [ClassDeclaration] returns its members, otherwise if node is |
1961 /// a [ClassTypeAlias] this returns an empty list. | 1977 /// a [ClassTypeAlias] this returns an empty list. |
1962 WithClause _withClause(Declaration node) { | 1978 WithClause _withClause(Declaration node) { |
1963 return node is ClassDeclaration | 1979 return node is ClassDeclaration |
1964 ? node.withClause | 1980 ? node.withClause |
1965 : (node as ClassTypeAlias).withClause; | 1981 : (node as ClassTypeAlias).withClause; |
1966 } | 1982 } |
1967 } | 1983 } |
OLD | NEW |