| 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 |
| 8 import '../elements/elements.dart' show ClassElement; | 8 IterableBase; |
| 9 import '../util/util.dart' show Link; | 9 import '../elements/elements.dart' show |
| 10 ClassElement; |
| 11 import '../util/enumset.dart' show |
| 12 EnumSet; |
| 13 import '../util/util.dart' show |
| 14 Link; |
| 15 |
| 16 /// Enum for the different kinds of instantiation of a class. |
| 17 enum Instantiation { |
| 18 UNINSTANTIATED, |
| 19 DIRECTLY_INSTANTIATED, |
| 20 INDIRECTLY_INSTANTIATED, |
| 21 } |
| 10 | 22 |
| 11 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. | 23 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. |
| 12 /// | 24 /// |
| 13 /// This is used by the [ClassWorld] to perform queries on subclass and subtype | 25 /// This is used by the [ClassWorld] to perform queries on subclass and subtype |
| 14 /// relations. | 26 /// relations. |
| 15 /// | 27 /// |
| 16 /// For this class hierarchy: | 28 /// For this class hierarchy: |
| 17 /// | 29 /// |
| 18 /// class A {} | 30 /// class A {} |
| 19 /// class B extends A {} | 31 /// class B extends A {} |
| 20 /// class C extends A {} | 32 /// class C extends A {} |
| 21 /// class D extends B {} | 33 /// class D extends B {} |
| 22 /// class E extends D {} | 34 /// class E extends D {} |
| 23 /// | 35 /// |
| 24 /// the [ClassHierarchyNode]s form this subclass tree: | 36 /// the [ClassHierarchyNode]s form this subclass tree: |
| 25 /// | 37 /// |
| 26 /// Object | 38 /// Object |
| 27 /// | | 39 /// | |
| 28 /// A | 40 /// A |
| 29 /// / \ | 41 /// / \ |
| 30 /// B C | 42 /// B C |
| 31 /// | | 43 /// | |
| 32 /// D | 44 /// D |
| 33 /// | | 45 /// | |
| 34 /// E | 46 /// E |
| 35 /// | 47 /// |
| 36 class ClassHierarchyNode { | 48 class ClassHierarchyNode { |
| 49 /// Enum set for selecting instantiated classes in |
| 50 /// [ClassHierarchyNode.subclassesByMask], |
| 51 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 52 static final EnumSet<Instantiation> INSTANTIATED = |
| 53 new EnumSet<Instantiation>.fromValues( |
| 54 const <Instantiation>[ |
| 55 Instantiation.DIRECTLY_INSTANTIATED, |
| 56 Instantiation.INDIRECTLY_INSTANTIATED], |
| 57 fixed: true); |
| 58 |
| 59 /// Enum set for selecting directly instantiated classes in |
| 60 /// [ClassHierarchyNode.subclassesByMask], |
| 61 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 62 static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = |
| 63 new EnumSet<Instantiation>.fromValues( |
| 64 const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], |
| 65 fixed: true); |
| 66 |
| 67 /// Enum set for selecting all classes in |
| 68 /// [ClassHierarchyNode.subclassesByMask], |
| 69 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 70 static final EnumSet<Instantiation> ALL = |
| 71 new EnumSet<Instantiation>.fromValues( |
| 72 Instantiation.values, |
| 73 fixed: true); |
| 74 |
| 75 /// Creates an enum set for selecting the returned classes in |
| 76 /// [ClassHierarchyNode.subclassesByMask], |
| 77 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 78 static EnumSet<Instantiation> createMask( |
| 79 {bool includeDirectlyInstantiated: true, |
| 80 bool includeIndirectlyInstantiated: true, |
| 81 bool includeUninstantiated: true}) { |
| 82 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); |
| 83 if (includeDirectlyInstantiated) { |
| 84 mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
| 85 } |
| 86 if (includeIndirectlyInstantiated) { |
| 87 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); |
| 88 } |
| 89 if (includeUninstantiated) { |
| 90 mask.add(Instantiation.UNINSTANTIATED); |
| 91 } |
| 92 return mask; |
| 93 } |
| 94 |
| 37 final ClassElement cls; | 95 final ClassElement cls; |
| 96 final EnumSet<Instantiation> _mask = |
| 97 new EnumSet<Instantiation>.fromValues( |
| 98 const <Instantiation>[Instantiation.UNINSTANTIATED]); |
| 99 |
| 38 ClassElement _leastUpperInstantiatedSubclass; | 100 ClassElement _leastUpperInstantiatedSubclass; |
| 39 | 101 |
| 40 /// `true` if [cls] has been directly instantiated. | 102 /// `true` if [cls] has been directly instantiated. |
| 41 /// | 103 /// |
| 42 /// For instance `C` but _not_ `B` in: | 104 /// For instance `C` but _not_ `B` in: |
| 43 /// class B {} | 105 /// class B {} |
| 44 /// class C extends B {} | 106 /// class C extends B {} |
| 45 /// main() => new C(); | 107 /// main() => new C(); |
| 46 /// | 108 /// |
| 47 bool isDirectlyInstantiated = false; | 109 bool get isDirectlyInstantiated => |
| 110 _mask.contains(Instantiation.DIRECTLY_INSTANTIATED); |
| 111 |
| 112 void set isDirectlyInstantiated(bool value) { |
| 113 if (value != isDirectlyInstantiated) { |
| 114 if (value) { |
| 115 _mask.remove(Instantiation.UNINSTANTIATED); |
| 116 _mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
| 117 } else { |
| 118 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); |
| 119 if (_mask.isEmpty) { |
| 120 _mask.add(Instantiation.UNINSTANTIATED); |
| 121 } |
| 122 } |
| 123 } |
| 124 } |
| 48 | 125 |
| 49 /// `true` if [cls] has been instantiated through subclasses. | 126 /// `true` if [cls] has been instantiated through subclasses. |
| 50 /// | 127 /// |
| 51 /// For instance `A` and `B` but _not_ `C` in: | 128 /// For instance `A` and `B` but _not_ `C` in: |
| 52 /// class A {} | 129 /// class A {} |
| 53 /// class B extends A {} | 130 /// class B extends A {} |
| 54 /// class C extends B {} | 131 /// class C extends B {} |
| 55 /// main() => [new B(), new C()]; | 132 /// main() => [new B(), new C()]; |
| 56 /// | 133 /// |
| 57 bool isIndirectlyInstantiated = false; | 134 bool get isIndirectlyInstantiated => |
| 135 _mask.contains(Instantiation.INDIRECTLY_INSTANTIATED); |
| 136 |
| 137 void set isIndirectlyInstantiated(bool value) { |
| 138 if (value != isIndirectlyInstantiated) { |
| 139 if (value) { |
| 140 _mask.remove(Instantiation.UNINSTANTIATED); |
| 141 _mask.add(Instantiation.INDIRECTLY_INSTANTIATED); |
| 142 } else { |
| 143 _mask.remove(Instantiation.INDIRECTLY_INSTANTIATED); |
| 144 if (_mask.isEmpty) { |
| 145 _mask.add(Instantiation.UNINSTANTIATED); |
| 146 } |
| 147 } |
| 148 } |
| 149 } |
| 58 | 150 |
| 59 /// The nodes for the direct subclasses of [cls]. | 151 /// The nodes for the direct subclasses of [cls]. |
| 60 Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>(); | 152 Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>(); |
| 61 | 153 |
| 62 ClassHierarchyNode(this.cls); | 154 ClassHierarchyNode(this.cls); |
| 63 | 155 |
| 64 /// Adds [subclass] as a direct subclass of [cls]. | 156 /// Adds [subclass] as a direct subclass of [cls]. |
| 65 void addDirectSubclass(ClassHierarchyNode subclass) { | 157 void addDirectSubclass(ClassHierarchyNode subclass) { |
| 66 assert(subclass.cls.superclass == cls); | 158 assert(subclass.cls.superclass == cls); |
| 67 assert(!_directSubclasses.contains(subclass)); | 159 assert(!_directSubclasses.contains(subclass)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 87 /// | 179 /// |
| 88 /// The directly instantiated, indirectly instantiated and uninstantiated | 180 /// The directly instantiated, indirectly instantiated and uninstantiated |
| 89 /// subclasses of [cls] are returned if [includeDirectlyInstantiated], | 181 /// subclasses of [cls] are returned if [includeDirectlyInstantiated], |
| 90 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, | 182 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, |
| 91 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. | 183 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. |
| 92 Iterable<ClassElement> subclasses( | 184 Iterable<ClassElement> subclasses( |
| 93 {bool includeDirectlyInstantiated: true, | 185 {bool includeDirectlyInstantiated: true, |
| 94 bool includeIndirectlyInstantiated: true, | 186 bool includeIndirectlyInstantiated: true, |
| 95 bool includeUninstantiated: true, | 187 bool includeUninstantiated: true, |
| 96 bool strict: false}) { | 188 bool strict: false}) { |
| 189 EnumSet<Instantiation> mask = createMask( |
| 190 includeDirectlyInstantiated: includeDirectlyInstantiated, |
| 191 includeIndirectlyInstantiated:includeIndirectlyInstantiated, |
| 192 includeUninstantiated: includeUninstantiated); |
| 193 return subclassesByMask(mask, strict: strict); |
| 194 } |
| 195 |
| 196 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 197 /// |
| 198 /// Subclasses are included if their instantiation properties intersect with |
| 199 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 200 /// `true`, [cls] itself is _not_ returned. |
| 201 Iterable<ClassElement> subclassesByMask( |
| 202 EnumSet<Instantiation> mask, |
| 203 {bool strict: false}) { |
| 97 return new ClassHierarchyNodeIterable( | 204 return new ClassHierarchyNodeIterable( |
| 98 this, | 205 this, mask, includeRoot: !strict); |
| 99 includeRoot: !strict, | |
| 100 includeDirectlyInstantiated: includeDirectlyInstantiated, | |
| 101 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | |
| 102 includeUninstantiated: includeUninstantiated); | |
| 103 } | 206 } |
| 104 | 207 |
| 105 /// Returns the most specific subclass of [cls] (including [cls]) that is | 208 /// Returns the most specific subclass of [cls] (including [cls]) that is |
| 106 /// directly instantiated or a superclass of all directly instantiated | 209 /// directly instantiated or a superclass of all directly instantiated |
| 107 /// subclasses. If [cls] is not instantiated, `null` is returned. | 210 /// subclasses. If [cls] is not instantiated, `null` is returned. |
| 108 ClassElement getLubOfInstantiatedSubclasses() { | 211 ClassElement getLubOfInstantiatedSubclasses() { |
| 109 if (!isInstantiated) return null; | 212 if (!isInstantiated) return null; |
| 110 if (_leastUpperInstantiatedSubclass == null) { | 213 if (_leastUpperInstantiatedSubclass == null) { |
| 111 _leastUpperInstantiatedSubclass = | 214 _leastUpperInstantiatedSubclass = |
| 112 _computeLeastUpperInstantiatedSubclass(); | 215 _computeLeastUpperInstantiatedSubclass(); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 /// | 371 /// |
| 269 /// The directly instantiated, indirectly instantiated and uninstantiated | 372 /// The directly instantiated, indirectly instantiated and uninstantiated |
| 270 /// subclasses of [cls] are returned if [includeDirectlyInstantiated], | 373 /// subclasses of [cls] are returned if [includeDirectlyInstantiated], |
| 271 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, | 374 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, |
| 272 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. | 375 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. |
| 273 Iterable<ClassElement> subclasses( | 376 Iterable<ClassElement> subclasses( |
| 274 {bool includeDirectlyInstantiated: true, | 377 {bool includeDirectlyInstantiated: true, |
| 275 bool includeIndirectlyInstantiated: true, | 378 bool includeIndirectlyInstantiated: true, |
| 276 bool includeUninstantiated: true, | 379 bool includeUninstantiated: true, |
| 277 bool strict: false}) { | 380 bool strict: false}) { |
| 278 return node.subclasses( | 381 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( |
| 279 strict: strict, | |
| 280 includeDirectlyInstantiated: includeDirectlyInstantiated, | 382 includeDirectlyInstantiated: includeDirectlyInstantiated, |
| 281 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | 383 includeIndirectlyInstantiated:includeIndirectlyInstantiated, |
| 282 includeUninstantiated: includeUninstantiated); | 384 includeUninstantiated: includeUninstantiated); |
| 385 return subclassesByMask(mask, strict: strict); |
| 386 } |
| 387 |
| 388 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 389 /// |
| 390 /// Subclasses are included if their instantiation properties intersect with |
| 391 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 392 /// `true`, [cls] itself is _not_ returned. |
| 393 Iterable<ClassElement> subclassesByMask( |
| 394 EnumSet<Instantiation> mask, |
| 395 {bool strict: false}) { |
| 396 return node.subclassesByMask(mask, strict: strict); |
| 283 } | 397 } |
| 284 | 398 |
| 285 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. | 399 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 286 /// | 400 /// |
| 287 /// The directly instantiated, indirectly instantiated and uninstantiated | 401 /// The directly instantiated, indirectly instantiated and uninstantiated |
| 288 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], | 402 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], |
| 289 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, | 403 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, |
| 290 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. | 404 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. |
| 291 Iterable<ClassElement> subtypes( | 405 Iterable<ClassElement> subtypes( |
| 292 {bool includeDirectlyInstantiated: true, | 406 {bool includeDirectlyInstantiated: true, |
| 293 bool includeIndirectlyInstantiated: true, | 407 bool includeIndirectlyInstantiated: true, |
| 294 bool includeUninstantiated: true, | 408 bool includeUninstantiated: true, |
| 295 bool strict: false}) { | 409 bool strict: false}) { |
| 410 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( |
| 411 includeDirectlyInstantiated: includeDirectlyInstantiated, |
| 412 includeIndirectlyInstantiated:includeIndirectlyInstantiated, |
| 413 includeUninstantiated: includeUninstantiated); |
| 414 return subtypesByMask(mask, strict: strict); |
| 415 } |
| 416 |
| 417 |
| 418 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 419 /// |
| 420 /// Subtypes are included if their instantiation properties intersect with |
| 421 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 422 /// `true`, [cls] itself is _not_ returned. |
| 423 Iterable<ClassElement> subtypesByMask( |
| 424 EnumSet<Instantiation> mask, |
| 425 {bool strict: false}) { |
| 296 if (_directSubtypes == null) { | 426 if (_directSubtypes == null) { |
| 297 return node.subclasses( | 427 return node.subclassesByMask( |
| 298 strict: strict, | 428 mask, |
| 299 includeDirectlyInstantiated: includeDirectlyInstantiated, | 429 strict: strict); |
| 300 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | |
| 301 includeUninstantiated: includeUninstantiated); | |
| 302 } | 430 } |
| 431 |
| 303 return new SubtypesIterable.SubtypesIterator(this, | 432 return new SubtypesIterable.SubtypesIterator(this, |
| 304 includeRoot: !strict, | 433 mask, |
| 305 includeDirectlyInstantiated: includeDirectlyInstantiated, | 434 includeRoot: !strict); |
| 306 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | |
| 307 includeUninstantiated: includeUninstantiated); | |
| 308 } | 435 } |
| 309 | 436 |
| 310 /// Adds [subtype] as a subtype of [cls]. | 437 /// Adds [subtype] as a subtype of [cls]. |
| 311 void addSubtype(ClassHierarchyNode subtype) { | 438 void addSubtype(ClassHierarchyNode subtype) { |
| 312 if (node.contains(subtype.cls)) { | 439 if (node.contains(subtype.cls)) { |
| 313 return; | 440 return; |
| 314 } | 441 } |
| 315 if (_directSubtypes == null) { | 442 if (_directSubtypes == null) { |
| 316 _directSubtypes = <ClassHierarchyNode>[subtype]; | 443 _directSubtypes = <ClassHierarchyNode>[subtype]; |
| 317 } else { | 444 } else { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 } | 532 } |
| 406 } | 533 } |
| 407 sb.write(']'); | 534 sb.write(']'); |
| 408 return sb.toString(); | 535 return sb.toString(); |
| 409 } | 536 } |
| 410 } | 537 } |
| 411 | 538 |
| 412 /// Iterable for subclasses of a [ClassHierarchyNode]. | 539 /// Iterable for subclasses of a [ClassHierarchyNode]. |
| 413 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { | 540 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { |
| 414 final ClassHierarchyNode root; | 541 final ClassHierarchyNode root; |
| 542 final EnumSet<Instantiation> mask; |
| 415 final bool includeRoot; | 543 final bool includeRoot; |
| 416 final bool includeDirectlyInstantiated; | |
| 417 final bool includeIndirectlyInstantiated; | |
| 418 final bool includeUninstantiated; | |
| 419 | 544 |
| 420 ClassHierarchyNodeIterable( | 545 ClassHierarchyNodeIterable( |
| 421 this.root, | 546 this.root, |
| 422 {this.includeRoot: true, | 547 this.mask, |
| 423 this.includeDirectlyInstantiated: true, | 548 {this.includeRoot: true}) { |
| 424 this.includeIndirectlyInstantiated: true, | |
| 425 this.includeUninstantiated: true}) { | |
| 426 if (root == null) throw new StateError("No root for iterable."); | 549 if (root == null) throw new StateError("No root for iterable."); |
| 427 } | 550 } |
| 428 | 551 |
| 429 @override | 552 @override |
| 430 Iterator<ClassElement> get iterator { | 553 Iterator<ClassElement> get iterator { |
| 431 return new ClassHierarchyNodeIterator(this); | 554 return new ClassHierarchyNodeIterator(this); |
| 432 } | 555 } |
| 433 } | 556 } |
| 434 | 557 |
| 435 /// Iterator for subclasses of a [ClassHierarchyNode]. | 558 /// Iterator for subclasses of a [ClassHierarchyNode]. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 448 /// | 571 /// |
| 449 /// This is `null` before the first call to [moveNext]. | 572 /// This is `null` before the first call to [moveNext]. |
| 450 Link<ClassHierarchyNode> stack; | 573 Link<ClassHierarchyNode> stack; |
| 451 | 574 |
| 452 ClassHierarchyNodeIterator(this.iterable); | 575 ClassHierarchyNodeIterator(this.iterable); |
| 453 | 576 |
| 454 ClassHierarchyNode get root => iterable.root; | 577 ClassHierarchyNode get root => iterable.root; |
| 455 | 578 |
| 456 bool get includeRoot => iterable.includeRoot; | 579 bool get includeRoot => iterable.includeRoot; |
| 457 | 580 |
| 458 bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated; | 581 EnumSet<Instantiation> get mask => iterable.mask; |
| 459 | 582 |
| 460 bool get includeIndirectlyInstantiated { | 583 bool get includeUninstantiated { |
| 461 return iterable.includeIndirectlyInstantiated; | 584 return mask.contains(Instantiation.UNINSTANTIATED); |
| 462 } | 585 } |
| 463 | 586 |
| 464 bool get includeUninstantiated => iterable.includeUninstantiated; | |
| 465 | |
| 466 @override | 587 @override |
| 467 ClassElement get current { | 588 ClassElement get current { |
| 468 return currentNode != null ? currentNode.cls : null; | 589 return currentNode != null ? currentNode.cls : null; |
| 469 } | 590 } |
| 470 | 591 |
| 471 @override | 592 @override |
| 472 bool moveNext() { | 593 bool moveNext() { |
| 473 if (stack == null) { | 594 if (stack == null) { |
| 474 // First call to moveNext | 595 // First call to moveNext |
| 475 stack = const Link<ClassHierarchyNode>().prepend(root); | 596 stack = const Link<ClassHierarchyNode>().prepend(root); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 504 } | 625 } |
| 505 if (_isValid(currentNode)) { | 626 if (_isValid(currentNode)) { |
| 506 return true; | 627 return true; |
| 507 } | 628 } |
| 508 } | 629 } |
| 509 } | 630 } |
| 510 | 631 |
| 511 /// Returns `true` if the class of [node] is a valid result for this iterator. | 632 /// Returns `true` if the class of [node] is a valid result for this iterator. |
| 512 bool _isValid(ClassHierarchyNode node) { | 633 bool _isValid(ClassHierarchyNode node) { |
| 513 if (!includeRoot && node == root) return false; | 634 if (!includeRoot && node == root) return false; |
| 514 if (includeDirectlyInstantiated && node.isDirectlyInstantiated) { | 635 return mask.intersects(node._mask); |
| 515 return true; | |
| 516 } | |
| 517 if (includeIndirectlyInstantiated && node.isIndirectlyInstantiated) { | |
| 518 return true; | |
| 519 } | |
| 520 if (includeUninstantiated && !node.isInstantiated) { | |
| 521 return true; | |
| 522 } | |
| 523 return false; | |
| 524 } | 636 } |
| 525 } | 637 } |
| 526 | 638 |
| 527 /// Iterable for the subtypes in a [ClassSet]. | 639 /// Iterable for the subtypes in a [ClassSet]. |
| 528 class SubtypesIterable extends IterableBase<ClassElement> { | 640 class SubtypesIterable extends IterableBase<ClassElement> { |
| 529 final ClassSet subtypeSet; | 641 final ClassSet subtypeSet; |
| 642 final EnumSet<Instantiation> mask; |
| 530 final bool includeRoot; | 643 final bool includeRoot; |
| 531 final bool includeDirectlyInstantiated; | |
| 532 final bool includeIndirectlyInstantiated; | |
| 533 final bool includeUninstantiated; | |
| 534 | 644 |
| 535 SubtypesIterable.SubtypesIterator( | 645 SubtypesIterable.SubtypesIterator( |
| 536 this.subtypeSet, | 646 this.subtypeSet, |
| 537 {this.includeRoot: true, | 647 this.mask, |
| 538 this.includeDirectlyInstantiated: true, | 648 {this.includeRoot: true}); |
| 539 this.includeIndirectlyInstantiated: true, | |
| 540 this.includeUninstantiated: true}); | |
| 541 | 649 |
| 542 @override | 650 @override |
| 543 Iterator<ClassElement> get iterator => new SubtypesIterator(this); | 651 Iterator<ClassElement> get iterator => new SubtypesIterator(this); |
| 544 } | 652 } |
| 545 | 653 |
| 546 /// Iterator for the subtypes in a [ClassSet]. | 654 /// Iterator for the subtypes in a [ClassSet]. |
| 547 class SubtypesIterator extends Iterator<ClassElement> { | 655 class SubtypesIterator extends Iterator<ClassElement> { |
| 548 final SubtypesIterable iterable; | 656 final SubtypesIterable iterable; |
| 549 Iterator<ClassElement> elements; | 657 Iterator<ClassElement> elements; |
| 550 Iterator<ClassHierarchyNode> hierarchyNodes; | 658 Iterator<ClassHierarchyNode> hierarchyNodes; |
| 551 | 659 |
| 552 SubtypesIterator(this.iterable); | 660 SubtypesIterator(this.iterable); |
| 553 | 661 |
| 554 bool get includeRoot => iterable.includeRoot; | 662 bool get includeRoot => iterable.includeRoot; |
| 555 | 663 |
| 556 bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated; | 664 EnumSet<Instantiation> get mask => iterable.mask; |
| 557 | |
| 558 bool get includeIndirectlyInstantiated { | |
| 559 return iterable.includeIndirectlyInstantiated; | |
| 560 } | |
| 561 | |
| 562 bool get includeUninstantiated => iterable.includeUninstantiated; | |
| 563 | 665 |
| 564 @override | 666 @override |
| 565 ClassElement get current { | 667 ClassElement get current { |
| 566 if (elements != null) { | 668 if (elements != null) { |
| 567 return elements.current; | 669 return elements.current; |
| 568 } | 670 } |
| 569 return null; | 671 return null; |
| 570 } | 672 } |
| 571 | 673 |
| 572 @override | 674 @override |
| 573 bool moveNext() { | 675 bool moveNext() { |
| 574 if (elements == null && hierarchyNodes == null) { | 676 if (elements == null && hierarchyNodes == null) { |
| 575 // Initial state. Iterate through subclasses. | 677 // Initial state. Iterate through subclasses. |
| 576 elements = iterable.subtypeSet.node.subclasses( | 678 elements = iterable.subtypeSet.node.subclassesByMask( |
| 577 strict: !includeRoot, | 679 mask, |
| 578 includeDirectlyInstantiated: includeDirectlyInstantiated, | 680 strict: !includeRoot).iterator; |
| 579 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | |
| 580 includeUninstantiated: includeUninstantiated).iterator; | |
| 581 } | 681 } |
| 582 if (elements != null && elements.moveNext()) { | 682 if (elements != null && elements.moveNext()) { |
| 583 return true; | 683 return true; |
| 584 } | 684 } |
| 585 if (hierarchyNodes == null) { | 685 if (hierarchyNodes == null) { |
| 586 // Start iterating through subtypes. | 686 // Start iterating through subtypes. |
| 587 hierarchyNodes = iterable.subtypeSet._directSubtypes.iterator; | 687 hierarchyNodes = iterable.subtypeSet._directSubtypes.iterator; |
| 588 } | 688 } |
| 589 while (hierarchyNodes.moveNext()) { | 689 while (hierarchyNodes.moveNext()) { |
| 590 elements = hierarchyNodes.current.subclasses( | 690 elements = hierarchyNodes.current.subclassesByMask(mask).iterator; |
| 591 includeDirectlyInstantiated: includeDirectlyInstantiated, | |
| 592 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | |
| 593 includeUninstantiated: includeUninstantiated).iterator; | |
| 594 if (elements.moveNext()) { | 691 if (elements.moveNext()) { |
| 595 return true; | 692 return true; |
| 596 } | 693 } |
| 597 } | 694 } |
| 598 return false; | 695 return false; |
| 599 } | 696 } |
| 600 } | 697 } |
| OLD | NEW |