| 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 library dart2js.world.class_set; | 5 library dart2js.world.class_set; |
| 6 | 6 |
| 7 import 'dart:collection' show IterableBase; | 7 import 'dart:collection' show IterableBase; |
| 8 | 8 |
| 9 import '../common.dart'; |
| 9 import '../elements/elements.dart' show ClassElement; | 10 import '../elements/elements.dart' show ClassElement; |
| 10 import '../util/enumset.dart' show EnumSet; | 11 import '../util/enumset.dart' show EnumSet; |
| 11 import '../util/util.dart' show Link; | 12 import '../util/util.dart' show Link; |
| 12 | 13 |
| 13 /// Enum for the different kinds of instantiation of a class. | 14 /// Enum for the different kinds of instantiation of a class. |
| 14 enum Instantiation { | 15 enum Instantiation { |
| 15 UNINSTANTIATED, | 16 UNINSTANTIATED, |
| 16 DIRECTLY_INSTANTIATED, | 17 DIRECTLY_INSTANTIATED, |
| 17 INDIRECTLY_INSTANTIATED, | 18 INDIRECTLY_INSTANTIATED, |
| 19 ABSTRACTLY_INSTANTIATED, |
| 18 } | 20 } |
| 19 | 21 |
| 20 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. | 22 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. |
| 21 /// | 23 /// |
| 22 /// This is used by the [ClosedWorld] to perform queries on subclass and subtype | 24 /// This is used by the [ClosedWorld] to perform queries on subclass and subtype |
| 23 /// relations. | 25 /// relations. |
| 24 /// | 26 /// |
| 25 /// For this class hierarchy: | 27 /// For this class hierarchy: |
| 26 /// | 28 /// |
| 27 /// class A {} | 29 /// class A {} |
| (...skipping 14 matching lines...) Expand all Loading... |
| 42 /// | | 44 /// | |
| 43 /// E | 45 /// E |
| 44 /// | 46 /// |
| 45 class ClassHierarchyNode { | 47 class ClassHierarchyNode { |
| 46 /// Enum set for selecting instantiated classes in | 48 /// Enum set for selecting instantiated classes in |
| 47 /// [ClassHierarchyNode.subclassesByMask], | 49 /// [ClassHierarchyNode.subclassesByMask], |
| 48 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 50 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 49 static final EnumSet<Instantiation> INSTANTIATED = | 51 static final EnumSet<Instantiation> INSTANTIATED = |
| 50 new EnumSet<Instantiation>.fromValues(const <Instantiation>[ | 52 new EnumSet<Instantiation>.fromValues(const <Instantiation>[ |
| 51 Instantiation.DIRECTLY_INSTANTIATED, | 53 Instantiation.DIRECTLY_INSTANTIATED, |
| 52 Instantiation.INDIRECTLY_INSTANTIATED | 54 Instantiation.INDIRECTLY_INSTANTIATED, |
| 55 Instantiation.ABSTRACTLY_INSTANTIATED, |
| 53 ], fixed: true); | 56 ], fixed: true); |
| 54 | 57 |
| 55 /// Enum set for selecting directly instantiated classes in | 58 /// Enum set for selecting directly and abstractly instantiated classes in |
| 56 /// [ClassHierarchyNode.subclassesByMask], | 59 /// [ClassHierarchyNode.subclassesByMask], |
| 57 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 60 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 58 static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = | 61 static final EnumSet<Instantiation> EXPLICITLY_INSTANTIATED = |
| 59 new EnumSet<Instantiation>.fromValues( | 62 new EnumSet<Instantiation>.fromValues(const <Instantiation>[ |
| 60 const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], | 63 Instantiation.DIRECTLY_INSTANTIATED, |
| 61 fixed: true); | 64 Instantiation.ABSTRACTLY_INSTANTIATED |
| 65 ], fixed: true); |
| 62 | 66 |
| 63 /// Enum set for selecting all classes in | 67 /// Enum set for selecting all classes in |
| 64 /// [ClassHierarchyNode.subclassesByMask], | 68 /// [ClassHierarchyNode.subclassesByMask], |
| 65 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 69 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 66 static final EnumSet<Instantiation> ALL = | 70 static final EnumSet<Instantiation> ALL = |
| 67 new EnumSet<Instantiation>.fromValues(Instantiation.values, fixed: true); | 71 new EnumSet<Instantiation>.fromValues(Instantiation.values, fixed: true); |
| 68 | 72 |
| 69 /// Creates an enum set for selecting the returned classes in | 73 /// Creates an enum set for selecting the returned classes in |
| 70 /// [ClassHierarchyNode.subclassesByMask], | 74 /// [ClassHierarchyNode.subclassesByMask], |
| 71 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 75 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 72 static EnumSet<Instantiation> createMask( | 76 static EnumSet<Instantiation> createMask( |
| 73 {bool includeDirectlyInstantiated: true, | 77 {bool includeDirectlyInstantiated: true, |
| 74 bool includeIndirectlyInstantiated: true, | 78 bool includeIndirectlyInstantiated: true, |
| 75 bool includeUninstantiated: true}) { | 79 bool includeUninstantiated: true, |
| 80 bool includeAbstractlyInstantiated: true}) { |
| 76 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); | 81 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); |
| 77 if (includeDirectlyInstantiated) { | 82 if (includeDirectlyInstantiated) { |
| 78 mask.add(Instantiation.DIRECTLY_INSTANTIATED); | 83 mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
| 79 } | 84 } |
| 80 if (includeIndirectlyInstantiated) { | 85 if (includeIndirectlyInstantiated) { |
| 81 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); | 86 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); |
| 82 } | 87 } |
| 83 if (includeUninstantiated) { | 88 if (includeUninstantiated) { |
| 84 mask.add(Instantiation.UNINSTANTIATED); | 89 mask.add(Instantiation.UNINSTANTIATED); |
| 85 } | 90 } |
| 91 if (includeAbstractlyInstantiated) { |
| 92 mask.add(Instantiation.ABSTRACTLY_INSTANTIATED); |
| 93 } |
| 86 return mask; | 94 return mask; |
| 87 } | 95 } |
| 88 | 96 |
| 89 final ClassHierarchyNode parentNode; | 97 final ClassHierarchyNode parentNode; |
| 90 final ClassElement cls; | 98 final ClassElement cls; |
| 91 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( | 99 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( |
| 92 const <Instantiation>[Instantiation.UNINSTANTIATED]); | 100 const <Instantiation>[Instantiation.UNINSTANTIATED]); |
| 93 | 101 |
| 94 ClassElement _leastUpperInstantiatedSubclass; | 102 ClassElement _leastUpperInstantiatedSubclass; |
| 95 int _instantiatedSubclassCount = 0; | 103 int _instantiatedSubclassCount = 0; |
| 96 | 104 |
| 97 /// `true` if [cls] has been directly instantiated. | 105 /// `true` if [cls] has been directly instantiated. |
| 98 /// | 106 /// |
| 99 /// For instance `C` but _not_ `B` in: | 107 /// For instance `C` but _not_ `B` in: |
| 100 /// class B {} | 108 /// class B {} |
| 101 /// class C extends B {} | 109 /// class C extends B {} |
| 102 /// main() => new C(); | 110 /// main() => new C(); |
| 103 /// | 111 /// |
| 104 bool get isDirectlyInstantiated => | 112 bool get isDirectlyInstantiated => |
| 105 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED); | 113 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED); |
| 106 | 114 |
| 107 void set isDirectlyInstantiated(bool value) { | 115 void set isDirectlyInstantiated(bool value) { |
| 108 if (value != isDirectlyInstantiated) { | 116 if (value != isDirectlyInstantiated) { |
| 109 ClassHierarchyNode parent = parentNode; | 117 _updateParentInstantiatedSubclassCount( |
| 110 if (value) { | 118 Instantiation.DIRECTLY_INSTANTIATED, |
| 111 _mask.remove(Instantiation.UNINSTANTIATED); | 119 add: value); |
| 112 _mask.add(Instantiation.DIRECTLY_INSTANTIATED); | 120 } |
| 113 while (parent != null) { | 121 } |
| 114 parent._updateInstantiatedSubclassCount(1); | 122 |
| 115 parent = parent.parentNode; | 123 /// `true` if [cls] has been abstractly instantiated. This means that at |
| 116 } | 124 /// runtime instances of [cls] or unknown subclasses of [cls] are assumed to |
| 117 } else { | 125 /// exist. |
| 118 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); | 126 /// |
| 119 if (_mask.isEmpty) { | 127 /// This is used to mark native and/or reflectable classes as instantiated. |
| 120 _mask.add(Instantiation.UNINSTANTIATED); | 128 /// For native classes we do not know the exact class that instantiates [cls] |
| 121 } | 129 /// so [cls] here represents the root of the subclasses. For reflectable |
| 122 while (parent != null) { | 130 /// classes we need event abstract classes to be 'live' even though they |
| 123 parent._updateInstantiatedSubclassCount(-1); | 131 /// cannot themselves be instantiated. |
| 124 parent = parent.parentNode; | 132 bool get isAbstractlyInstantiated => |
| 125 } | 133 _mask.contains(Instantiation.ABSTRACTLY_INSTANTIATED); |
| 134 |
| 135 void set isAbstractlyInstantiated(bool value) { |
| 136 if (value != isAbstractlyInstantiated) { |
| 137 _updateParentInstantiatedSubclassCount( |
| 138 Instantiation.ABSTRACTLY_INSTANTIATED, |
| 139 add: value); |
| 140 } |
| 141 } |
| 142 |
| 143 /// `true` if [cls] is either directly or abstractly instantiated. |
| 144 bool get isExplicitlyInstantiated => |
| 145 isDirectlyInstantiated || isAbstractlyInstantiated; |
| 146 |
| 147 void _updateParentInstantiatedSubclassCount(Instantiation instantiation, |
| 148 {bool add}) { |
| 149 ClassHierarchyNode parent = parentNode; |
| 150 if (add) { |
| 151 _mask.remove(Instantiation.UNINSTANTIATED); |
| 152 _mask.add(instantiation); |
| 153 while (parent != null) { |
| 154 parent._updateInstantiatedSubclassCount(1); |
| 155 parent = parent.parentNode; |
| 156 } |
| 157 } else { |
| 158 _mask.remove(instantiation); |
| 159 if (_mask.isEmpty) { |
| 160 _mask.add(Instantiation.UNINSTANTIATED); |
| 161 } |
| 162 while (parent != null) { |
| 163 parent._updateInstantiatedSubclassCount(-1); |
| 164 parent = parent.parentNode; |
| 126 } | 165 } |
| 127 } | 166 } |
| 128 } | 167 } |
| 129 | 168 |
| 130 /// `true` if [cls] has been instantiated through subclasses. | 169 /// `true` if [cls] has been instantiated through subclasses. |
| 131 /// | 170 /// |
| 132 /// For instance `A` and `B` but _not_ `C` in: | 171 /// For instance `A` and `B` but _not_ `C` in: |
| 133 /// class A {} | 172 /// class A {} |
| 134 /// class B extends A {} | 173 /// class B extends A {} |
| 135 /// class C extends B {} | 174 /// class C extends B {} |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 /// This means that [other] is a subclass of [cls]. | 220 /// This means that [other] is a subclass of [cls]. |
| 182 bool contains(ClassElement other) { | 221 bool contains(ClassElement other) { |
| 183 while (other != null) { | 222 while (other != null) { |
| 184 if (cls == other) return true; | 223 if (cls == other) return true; |
| 185 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; | 224 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; |
| 186 other = other.superclass; | 225 other = other.superclass; |
| 187 } | 226 } |
| 188 return false; | 227 return false; |
| 189 } | 228 } |
| 190 | 229 |
| 191 /// `true` if [cls] has been directly or indirectly instantiated. | 230 /// `true` if [cls] has been directly, indirectly, or abstractly instantiated. |
| 192 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; | 231 bool get isInstantiated => |
| 232 isExplicitlyInstantiated || isIndirectlyInstantiated; |
| 193 | 233 |
| 194 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 234 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 195 /// | 235 /// |
| 196 /// Subclasses are included if their instantiation properties intersect with | 236 /// Subclasses are included if their instantiation properties intersect with |
| 197 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 237 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 198 /// `true`, [cls] itself is _not_ returned. | 238 /// `true`, [cls] itself is _not_ returned. |
| 199 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, | 239 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, |
| 200 {bool strict: false}) { | 240 {bool strict: false}) { |
| 201 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); | 241 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); |
| 202 } | 242 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 ClassElement getLubOfInstantiatedSubclasses() { | 303 ClassElement getLubOfInstantiatedSubclasses() { |
| 264 if (!isInstantiated) return null; | 304 if (!isInstantiated) return null; |
| 265 if (_leastUpperInstantiatedSubclass == null) { | 305 if (_leastUpperInstantiatedSubclass == null) { |
| 266 _leastUpperInstantiatedSubclass = | 306 _leastUpperInstantiatedSubclass = |
| 267 _computeLeastUpperInstantiatedSubclass(); | 307 _computeLeastUpperInstantiatedSubclass(); |
| 268 } | 308 } |
| 269 return _leastUpperInstantiatedSubclass; | 309 return _leastUpperInstantiatedSubclass; |
| 270 } | 310 } |
| 271 | 311 |
| 272 ClassElement _computeLeastUpperInstantiatedSubclass() { | 312 ClassElement _computeLeastUpperInstantiatedSubclass() { |
| 273 if (isDirectlyInstantiated) { | 313 if (isExplicitlyInstantiated) { |
| 274 return cls; | 314 return cls; |
| 275 } | 315 } |
| 316 if (!isInstantiated) { |
| 317 return null; |
| 318 } |
| 276 ClassHierarchyNode subclass; | 319 ClassHierarchyNode subclass; |
| 277 for (Link<ClassHierarchyNode> link = _directSubclasses; | 320 for (Link<ClassHierarchyNode> link = _directSubclasses; |
| 278 !link.isEmpty; | 321 !link.isEmpty; |
| 279 link = link.tail) { | 322 link = link.tail) { |
| 280 if (link.head.isInstantiated) { | 323 if (link.head.isInstantiated) { |
| 281 if (subclass == null) { | 324 if (subclass == null) { |
| 282 subclass = link.head; | 325 subclass = link.head; |
| 283 } else { | 326 } else { |
| 284 return cls; | 327 return cls; |
| 285 } | 328 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 304 if (cls.isAbstract) { | 347 if (cls.isAbstract) { |
| 305 sb.write('abstract '); | 348 sb.write('abstract '); |
| 306 } | 349 } |
| 307 sb.write('class ${cls.name}:'); | 350 sb.write('class ${cls.name}:'); |
| 308 if (isDirectlyInstantiated) { | 351 if (isDirectlyInstantiated) { |
| 309 sb.write(' directly'); | 352 sb.write(' directly'); |
| 310 } | 353 } |
| 311 if (isIndirectlyInstantiated) { | 354 if (isIndirectlyInstantiated) { |
| 312 sb.write(' indirectly'); | 355 sb.write(' indirectly'); |
| 313 } | 356 } |
| 357 if (isAbstractlyInstantiated) { |
| 358 sb.write(' abstractly'); |
| 359 } |
| 314 sb.write(' ['); | 360 sb.write(' ['); |
| 315 if (_directSubclasses.isEmpty) { | 361 if (_directSubclasses.isEmpty) { |
| 316 sb.write(']'); | 362 sb.write(']'); |
| 317 } else { | 363 } else { |
| 318 var subclasses = _directSubclasses; | 364 var subclasses = _directSubclasses; |
| 319 if (sorted) { | 365 if (sorted) { |
| 320 subclasses = _directSubclasses.toList() | 366 subclasses = _directSubclasses.toList() |
| 321 ..sort((a, b) { | 367 ..sort((a, b) { |
| 322 return a.cls.name.compareTo(b.cls.name); | 368 return a.cls.name.compareTo(b.cls.name); |
| 323 }); | 369 }); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 | 478 |
| 433 ClassSet(this.node); | 479 ClassSet(this.node); |
| 434 | 480 |
| 435 ClassElement get cls => node.cls; | 481 ClassElement get cls => node.cls; |
| 436 | 482 |
| 437 /// Returns the number of directly instantiated subtypes of [cls]. | 483 /// Returns the number of directly instantiated subtypes of [cls]. |
| 438 int get instantiatedSubtypeCount { | 484 int get instantiatedSubtypeCount { |
| 439 int count = node.instantiatedSubclassCount; | 485 int count = node.instantiatedSubclassCount; |
| 440 if (_subtypes != null) { | 486 if (_subtypes != null) { |
| 441 for (ClassHierarchyNode subtypeNode in _subtypes) { | 487 for (ClassHierarchyNode subtypeNode in _subtypes) { |
| 442 if (subtypeNode.isDirectlyInstantiated) { | 488 if (subtypeNode.isExplicitlyInstantiated) { |
| 443 count++; | 489 count++; |
| 444 } | 490 } |
| 445 count += subtypeNode.instantiatedSubclassCount; | 491 count += subtypeNode.instantiatedSubclassCount; |
| 446 } | 492 } |
| 447 } | 493 } |
| 448 return count; | 494 return count; |
| 449 } | 495 } |
| 450 | 496 |
| 451 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of | 497 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of |
| 452 /// [cls]. | 498 /// [cls]. |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 /// directly instantiated or a superclass of all directly instantiated | 686 /// directly instantiated or a superclass of all directly instantiated |
| 641 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. | 687 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. |
| 642 ClassElement getLubOfInstantiatedSubtypes() { | 688 ClassElement getLubOfInstantiatedSubtypes() { |
| 643 if (_leastUpperInstantiatedSubtype == null) { | 689 if (_leastUpperInstantiatedSubtype == null) { |
| 644 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); | 690 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); |
| 645 } | 691 } |
| 646 return _leastUpperInstantiatedSubtype; | 692 return _leastUpperInstantiatedSubtype; |
| 647 } | 693 } |
| 648 | 694 |
| 649 ClassElement _computeLeastUpperInstantiatedSubtype() { | 695 ClassElement _computeLeastUpperInstantiatedSubtype() { |
| 650 if (node.isDirectlyInstantiated) { | 696 if (node.isExplicitlyInstantiated) { |
| 651 return cls; | 697 return cls; |
| 652 } | 698 } |
| 653 if (_subtypes == null) { | 699 if (_subtypes == null) { |
| 654 return node.getLubOfInstantiatedSubclasses(); | 700 return node.getLubOfInstantiatedSubclasses(); |
| 655 } | 701 } |
| 656 ClassHierarchyNode subtype; | 702 ClassHierarchyNode subtype; |
| 657 if (node.isInstantiated) { | 703 if (node.isInstantiated) { |
| 658 subtype = node; | 704 subtype = node; |
| 659 } | 705 } |
| 660 for (ClassHierarchyNode subnode in _subtypes) { | 706 for (ClassHierarchyNode subnode in _subtypes) { |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 STOP, | 900 STOP, |
| 855 | 901 |
| 856 /// Iteration skips the subclasses of the current class. | 902 /// Iteration skips the subclasses of the current class. |
| 857 SKIP_SUBCLASSES, | 903 SKIP_SUBCLASSES, |
| 858 } | 904 } |
| 859 | 905 |
| 860 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] | 906 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] |
| 861 /// and [ClassSet]. The return value controls the continued iteration. If `null` | 907 /// and [ClassSet]. The return value controls the continued iteration. If `null` |
| 862 /// is returned, iteration continues to the end. | 908 /// is returned, iteration continues to the end. |
| 863 typedef IterationStep ForEachFunction(ClassElement cls); | 909 typedef IterationStep ForEachFunction(ClassElement cls); |
| OLD | NEW |