| 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 '../elements/elements.dart' show ClassElement; | 9 import '../elements/elements.dart' show ClassElement; |
| 10 import '../elements/entities.dart' show ClassEntity; | 10 import '../elements/entities.dart' show ClassEntity; |
| 11 import '../util/enumset.dart' show EnumSet; | 11 import '../util/enumset.dart' show EnumSet; |
| 12 import '../util/util.dart' show Link; | 12 import '../util/util.dart' show Link; |
| 13 | 13 |
| 14 /// Enum for the different kinds of instantiation of a class. | 14 /// Enum for the different kinds of instantiation of a class. |
| 15 enum Instantiation { | 15 enum Instantiation { |
| 16 UNINSTANTIATED, | 16 UNINSTANTIATED, |
| 17 DIRECTLY_INSTANTIATED, | 17 DIRECTLY_INSTANTIATED, |
| 18 INDIRECTLY_INSTANTIATED, | 18 INDIRECTLY_INSTANTIATED, |
| 19 ABSTRACTLY_INSTANTIATED, | 19 ABSTRACTLY_INSTANTIATED, |
| 20 } | 20 } |
| 21 | 21 |
| 22 /// 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 [ClassEntity]s. |
| 23 /// | 23 /// |
| 24 /// 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 |
| 25 /// relations. | 25 /// relations. |
| 26 /// | 26 /// |
| 27 /// For this class hierarchy: | 27 /// For this class hierarchy: |
| 28 /// | 28 /// |
| 29 /// class A {} | 29 /// class A {} |
| 30 /// class B extends A {} | 30 /// class B extends A {} |
| 31 /// class C extends A {} | 31 /// class C extends A {} |
| 32 /// class D extends B {} | 32 /// class D extends B {} |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 return mask; | 94 return mask; |
| 95 } | 95 } |
| 96 | 96 |
| 97 final ClassHierarchyNode parentNode; | 97 final ClassHierarchyNode parentNode; |
| 98 final ClassEntity cls; | 98 final ClassEntity cls; |
| 99 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( | 99 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( |
| 100 const <Instantiation>[Instantiation.UNINSTANTIATED]); | 100 const <Instantiation>[Instantiation.UNINSTANTIATED]); |
| 101 | 101 |
| 102 final int hierarchyDepth; | 102 final int hierarchyDepth; |
| 103 | 103 |
| 104 ClassElement _leastUpperInstantiatedSubclass; | 104 ClassEntity _leastUpperInstantiatedSubclass; |
| 105 int _instantiatedSubclassCount = 0; | 105 int _instantiatedSubclassCount = 0; |
| 106 | 106 |
| 107 /// `true` if [cls] has been directly instantiated. | 107 /// `true` if [cls] has been directly instantiated. |
| 108 /// | 108 /// |
| 109 /// For instance `C` but _not_ `B` in: | 109 /// For instance `C` but _not_ `B` in: |
| 110 /// class B {} | 110 /// class B {} |
| 111 /// class C extends B {} | 111 /// class C extends B {} |
| 112 /// main() => new C(); | 112 /// main() => new C(); |
| 113 /// | 113 /// |
| 114 bool get isDirectlyInstantiated => | 114 bool get isDirectlyInstantiated => |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 | 230 |
| 231 /// `true` if [cls] has been directly, indirectly, or abstractly instantiated. | 231 /// `true` if [cls] has been directly, indirectly, or abstractly instantiated. |
| 232 bool get isInstantiated => | 232 bool get isInstantiated => |
| 233 isExplicitlyInstantiated || isIndirectlyInstantiated; | 233 isExplicitlyInstantiated || isIndirectlyInstantiated; |
| 234 | 234 |
| 235 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 235 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 236 /// | 236 /// |
| 237 /// Subclasses are included if their instantiation properties intersect with | 237 /// Subclasses are included if their instantiation properties intersect with |
| 238 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 238 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 239 /// `true`, [cls] itself is _not_ returned. | 239 /// `true`, [cls] itself is _not_ returned. |
| 240 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, | 240 Iterable<ClassEntity> subclassesByMask(EnumSet<Instantiation> mask, |
| 241 {bool strict: false}) { | 241 {bool strict: false}) { |
| 242 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); | 242 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); |
| 243 } | 243 } |
| 244 | 244 |
| 245 /// Applies [predicate] to each subclass of [cls] matching the criteria | 245 /// Applies [predicate] to each subclass of [cls] matching the criteria |
| 246 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 246 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 247 /// class, visitation is stopped immediately and the function returns `true`. | 247 /// class, visitation is stopped immediately and the function returns `true`. |
| 248 /// | 248 /// |
| 249 /// [predicate] is applied to subclasses if their instantiation properties | 249 /// [predicate] is applied to subclasses if their instantiation properties |
| 250 /// intersect with their corresponding [Instantiation] values in [mask]. If | 250 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 251 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 251 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 252 bool anySubclass( | 252 bool anySubclass(bool predicate(ClassEntity cls), EnumSet<Instantiation> mask, |
| 253 bool predicate(ClassElement cls), EnumSet<Instantiation> mask, | |
| 254 {bool strict: false}) { | 253 {bool strict: false}) { |
| 255 IterationStep wrapper(ClassElement cls) { | 254 IterationStep wrapper(ClassEntity cls) { |
| 256 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; | 255 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; |
| 257 } | 256 } |
| 258 | 257 |
| 259 return forEachSubclass(wrapper, mask, strict: strict) == IterationStep.STOP; | 258 return forEachSubclass(wrapper, mask, strict: strict) == IterationStep.STOP; |
| 260 } | 259 } |
| 261 | 260 |
| 262 /// Applies [f] to each subclass of [cls] matching the criteria specified by | 261 /// Applies [f] to each subclass of [cls] matching the criteria specified by |
| 263 /// [mask] and [strict]. | 262 /// [mask] and [strict]. |
| 264 /// | 263 /// |
| 265 /// [f] is a applied to subclasses if their instantiation properties intersect | 264 /// [f] is a applied to subclasses if their instantiation properties intersect |
| (...skipping 28 matching lines...) Expand all Loading... |
| 294 } | 293 } |
| 295 if (nextStep == IterationStep.STOP) { | 294 if (nextStep == IterationStep.STOP) { |
| 296 return nextStep; | 295 return nextStep; |
| 297 } | 296 } |
| 298 return IterationStep.CONTINUE; | 297 return IterationStep.CONTINUE; |
| 299 } | 298 } |
| 300 | 299 |
| 301 /// Returns the most specific subclass of [cls] (including [cls]) that is | 300 /// Returns the most specific subclass of [cls] (including [cls]) that is |
| 302 /// directly instantiated or a superclass of all directly instantiated | 301 /// directly instantiated or a superclass of all directly instantiated |
| 303 /// subclasses. If [cls] is not instantiated, `null` is returned. | 302 /// subclasses. If [cls] is not instantiated, `null` is returned. |
| 304 ClassElement getLubOfInstantiatedSubclasses() { | 303 ClassEntity getLubOfInstantiatedSubclasses() { |
| 305 if (!isInstantiated) return null; | 304 if (!isInstantiated) return null; |
| 306 if (_leastUpperInstantiatedSubclass == null) { | 305 if (_leastUpperInstantiatedSubclass == null) { |
| 307 _leastUpperInstantiatedSubclass = | 306 _leastUpperInstantiatedSubclass = |
| 308 _computeLeastUpperInstantiatedSubclass(); | 307 _computeLeastUpperInstantiatedSubclass(); |
| 309 } | 308 } |
| 310 return _leastUpperInstantiatedSubclass; | 309 return _leastUpperInstantiatedSubclass; |
| 311 } | 310 } |
| 312 | 311 |
| 313 ClassElement _computeLeastUpperInstantiatedSubclass() { | 312 ClassEntity _computeLeastUpperInstantiatedSubclass() { |
| 314 if (isExplicitlyInstantiated) { | 313 if (isExplicitlyInstantiated) { |
| 315 return cls; | 314 return cls; |
| 316 } | 315 } |
| 317 if (!isInstantiated) { | 316 if (!isInstantiated) { |
| 318 return null; | 317 return null; |
| 319 } | 318 } |
| 320 ClassHierarchyNode subclass; | 319 ClassHierarchyNode subclass; |
| 321 for (Link<ClassHierarchyNode> link = _directSubclasses; | 320 for (Link<ClassHierarchyNode> link = _directSubclasses; |
| 322 !link.isEmpty; | 321 !link.isEmpty; |
| 323 link = link.tail) { | 322 link = link.tail) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 StringBuffer sb = new StringBuffer(); | 404 StringBuffer sb = new StringBuffer(); |
| 406 printOn(sb, indentation, | 405 printOn(sb, indentation, |
| 407 instantiatedOnly: instantiatedOnly, withRespectTo: withRespectTo); | 406 instantiatedOnly: instantiatedOnly, withRespectTo: withRespectTo); |
| 408 return sb.toString(); | 407 return sb.toString(); |
| 409 } | 408 } |
| 410 | 409 |
| 411 String toString() => cls.toString(); | 410 String toString() => cls.toString(); |
| 412 } | 411 } |
| 413 | 412 |
| 414 /// Object holding the subclass and subtype relation for a single | 413 /// Object holding the subclass and subtype relation for a single |
| 415 /// [ClassElement]. | 414 /// [ClassEntity]. |
| 416 /// | 415 /// |
| 417 /// The subclass relation for a class `C` is modelled through a reference to | 416 /// The subclass relation for a class `C` is modelled through a reference to |
| 418 /// the [ClassHierarchyNode] for `C` in the global [ClassHierarchyNode] tree | 417 /// the [ClassHierarchyNode] for `C` in the global [ClassHierarchyNode] tree |
| 419 /// computed in [World]. | 418 /// computed in [World]. |
| 420 /// | 419 /// |
| 421 /// The subtype relation for a class `C` is modelled through a collection of | 420 /// The subtype relation for a class `C` is modelled through a collection of |
| 422 /// disjoint [ClassHierarchyNode] subtrees. The subclasses of `C`, modelled | 421 /// disjoint [ClassHierarchyNode] subtrees. The subclasses of `C`, modelled |
| 423 /// through the aforementioned [ClassHierarchyNode] pointer, are extended with | 422 /// through the aforementioned [ClassHierarchyNode] pointer, are extended with |
| 424 /// the subtypes that do not extend `C` through a list of additional | 423 /// the subtypes that do not extend `C` through a list of additional |
| 425 /// [ClassHierarchyNode] nodes. This list is normalized to contain only the | 424 /// [ClassHierarchyNode] nodes. This list is normalized to contain only the |
| (...skipping 24 matching lines...) Expand all Loading... |
| 450 /// The subtypes `B` and `E` are not directly modeled because they are implied | 449 /// The subtypes `B` and `E` are not directly modeled because they are implied |
| 451 /// by their subclass relation to `A` and `D`, repectively. This can be seen | 450 /// by their subclass relation to `A` and `D`, repectively. This can be seen |
| 452 /// if we expand the subclass subtrees: | 451 /// if we expand the subclass subtrees: |
| 453 /// | 452 /// |
| 454 /// A -> [C, D, F] | 453 /// A -> [C, D, F] |
| 455 /// | | | 454 /// | | |
| 456 /// B E | 455 /// B E |
| 457 /// | 456 /// |
| 458 class ClassSet { | 457 class ClassSet { |
| 459 final ClassHierarchyNode node; | 458 final ClassHierarchyNode node; |
| 460 ClassElement _leastUpperInstantiatedSubtype; | 459 ClassEntity _leastUpperInstantiatedSubtype; |
| 461 | 460 |
| 462 /// A list of the class hierarchy nodes for the subtypes that declare a | 461 /// A list of the class hierarchy nodes for the subtypes that declare a |
| 463 /// subtype relationship to [cls] either directly or indirectly. | 462 /// subtype relationship to [cls] either directly or indirectly. |
| 464 /// | 463 /// |
| 465 /// For instance | 464 /// For instance |
| 466 /// | 465 /// |
| 467 /// class A {} | 466 /// class A {} |
| 468 /// class B extends A {} | 467 /// class B extends A {} |
| 469 /// class C implements B {} | 468 /// class C implements B {} |
| 470 /// class D implements A {} | 469 /// class D implements A {} |
| 471 /// class E extends D {} | 470 /// class E extends D {} |
| 472 /// | 471 /// |
| 473 /// The class hierarchy nodes for classes `C` and `D` are in [_subtypes]. `C` | 472 /// The class hierarchy nodes for classes `C` and `D` are in [_subtypes]. `C` |
| 474 /// because it implements `A` through `B` and `D` because it implements `A` | 473 /// because it implements `A` through `B` and `D` because it implements `A` |
| 475 /// directly. `E` also implements `A` through its extension of `D` and it is | 474 /// directly. `E` also implements `A` through its extension of `D` and it is |
| 476 /// therefore included through the class hierarchy node for `D`. | 475 /// therefore included through the class hierarchy node for `D`. |
| 477 /// | 476 /// |
| 478 List<ClassHierarchyNode> _subtypes; | 477 List<ClassHierarchyNode> _subtypes; |
| 479 | 478 |
| 480 ClassSet(this.node); | 479 ClassSet(this.node); |
| 481 | 480 |
| 482 ClassElement get cls => node.cls; | 481 ClassEntity get cls => node.cls; |
| 483 | 482 |
| 484 /// Returns the number of directly instantiated subtypes of [cls]. | 483 /// Returns the number of directly instantiated subtypes of [cls]. |
| 485 int get instantiatedSubtypeCount { | 484 int get instantiatedSubtypeCount { |
| 486 int count = node.instantiatedSubclassCount; | 485 int count = node.instantiatedSubclassCount; |
| 487 if (_subtypes != null) { | 486 if (_subtypes != null) { |
| 488 for (ClassHierarchyNode subtypeNode in _subtypes) { | 487 for (ClassHierarchyNode subtypeNode in _subtypes) { |
| 489 if (subtypeNode.isExplicitlyInstantiated) { | 488 if (subtypeNode.isExplicitlyInstantiated) { |
| 490 count++; | 489 count++; |
| 491 } | 490 } |
| 492 count += subtypeNode.instantiatedSubclassCount; | 491 count += subtypeNode.instantiatedSubclassCount; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 510 | 509 |
| 511 Iterable<ClassHierarchyNode> get subtypeNodes { | 510 Iterable<ClassHierarchyNode> get subtypeNodes { |
| 512 return _subtypes ?? const <ClassHierarchyNode>[]; | 511 return _subtypes ?? const <ClassHierarchyNode>[]; |
| 513 } | 512 } |
| 514 | 513 |
| 515 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 514 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 516 /// | 515 /// |
| 517 /// Subclasses are included if their instantiation properties intersect with | 516 /// Subclasses are included if their instantiation properties intersect with |
| 518 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 517 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 519 /// `true`, [cls] itself is _not_ returned. | 518 /// `true`, [cls] itself is _not_ returned. |
| 520 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, | 519 Iterable<ClassEntity> subclassesByMask(EnumSet<Instantiation> mask, |
| 521 {bool strict: false}) { | 520 {bool strict: false}) { |
| 522 return node.subclassesByMask(mask, strict: strict); | 521 return node.subclassesByMask(mask, strict: strict); |
| 523 } | 522 } |
| 524 | 523 |
| 525 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. | 524 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 526 /// | 525 /// |
| 527 /// The directly instantiated, indirectly instantiated and uninstantiated | 526 /// The directly instantiated, indirectly instantiated and uninstantiated |
| 528 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], | 527 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], |
| 529 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, | 528 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, |
| 530 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. | 529 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. |
| 531 Iterable<ClassElement> subtypes( | 530 Iterable<ClassEntity> subtypes( |
| 532 {bool includeDirectlyInstantiated: true, | 531 {bool includeDirectlyInstantiated: true, |
| 533 bool includeIndirectlyInstantiated: true, | 532 bool includeIndirectlyInstantiated: true, |
| 534 bool includeUninstantiated: true, | 533 bool includeUninstantiated: true, |
| 535 bool strict: false}) { | 534 bool strict: false}) { |
| 536 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( | 535 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( |
| 537 includeDirectlyInstantiated: includeDirectlyInstantiated, | 536 includeDirectlyInstantiated: includeDirectlyInstantiated, |
| 538 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | 537 includeIndirectlyInstantiated: includeIndirectlyInstantiated, |
| 539 includeUninstantiated: includeUninstantiated); | 538 includeUninstantiated: includeUninstantiated); |
| 540 return subtypesByMask(mask, strict: strict); | 539 return subtypesByMask(mask, strict: strict); |
| 541 } | 540 } |
| 542 | 541 |
| 543 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. | 542 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 544 /// | 543 /// |
| 545 /// Subtypes are included if their instantiation properties intersect with | 544 /// Subtypes are included if their instantiation properties intersect with |
| 546 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 545 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 547 /// `true`, [cls] itself is _not_ returned. | 546 /// `true`, [cls] itself is _not_ returned. |
| 548 Iterable<ClassElement> subtypesByMask(EnumSet<Instantiation> mask, | 547 Iterable<ClassEntity> subtypesByMask(EnumSet<Instantiation> mask, |
| 549 {bool strict: false}) { | 548 {bool strict: false}) { |
| 550 if (_subtypes == null) { | 549 if (_subtypes == null) { |
| 551 return node.subclassesByMask(mask, strict: strict); | 550 return node.subclassesByMask(mask, strict: strict); |
| 552 } | 551 } |
| 553 | 552 |
| 554 return new SubtypesIterable.SubtypesIterator(this, mask, | 553 return new SubtypesIterable.SubtypesIterator(this, mask, |
| 555 includeRoot: !strict); | 554 includeRoot: !strict); |
| 556 } | 555 } |
| 557 | 556 |
| 558 /// Applies [predicate] to each subclass of [cls] matching the criteria | 557 /// Applies [predicate] to each subclass of [cls] matching the criteria |
| 559 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 558 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 560 /// class, visitation is stopped immediately and the function returns `true`. | 559 /// class, visitation is stopped immediately and the function returns `true`. |
| 561 /// | 560 /// |
| 562 /// [predicate] is applied to subclasses if their instantiation properties | 561 /// [predicate] is applied to subclasses if their instantiation properties |
| 563 /// intersect with their corresponding [Instantiation] values in [mask]. If | 562 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 564 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 563 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 565 bool anySubclass( | 564 bool anySubclass(bool predicate(ClassEntity cls), EnumSet<Instantiation> mask, |
| 566 bool predicate(ClassElement cls), EnumSet<Instantiation> mask, | |
| 567 {bool strict: false}) { | 565 {bool strict: false}) { |
| 568 return node.anySubclass(predicate, mask, strict: strict); | 566 return node.anySubclass(predicate, mask, strict: strict); |
| 569 } | 567 } |
| 570 | 568 |
| 571 /// Applies [f] to each subclass of [cls] matching the criteria specified by | 569 /// Applies [f] to each subclass of [cls] matching the criteria specified by |
| 572 /// [mask] and [strict]. | 570 /// [mask] and [strict]. |
| 573 /// | 571 /// |
| 574 /// [f] is a applied to subclasses if their instantiation properties intersect | 572 /// [f] is a applied to subclasses if their instantiation properties intersect |
| 575 /// with their corresponding [Instantiation] values in [mask]. If [strict] is | 573 /// with their corresponding [Instantiation] values in [mask]. If [strict] is |
| 576 /// `true`, [f] is _not_ called on [cls] itself. | 574 /// `true`, [f] is _not_ called on [cls] itself. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 587 return node.forEachSubclass(f, mask, strict: strict); | 585 return node.forEachSubclass(f, mask, strict: strict); |
| 588 } | 586 } |
| 589 | 587 |
| 590 /// Applies [predicate] to each subtype of [cls] matching the criteria | 588 /// Applies [predicate] to each subtype of [cls] matching the criteria |
| 591 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 589 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 592 /// class, visitation is stopped immediately and the function returns `true`. | 590 /// class, visitation is stopped immediately and the function returns `true`. |
| 593 /// | 591 /// |
| 594 /// [predicate] is applied to subtypes if their instantiation properties | 592 /// [predicate] is applied to subtypes if their instantiation properties |
| 595 /// intersect with their corresponding [Instantiation] values in [mask]. If | 593 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 596 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 594 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 597 bool anySubtype(bool predicate(ClassElement cls), EnumSet<Instantiation> mask, | 595 bool anySubtype(bool predicate(ClassEntity cls), EnumSet<Instantiation> mask, |
| 598 {bool strict: false}) { | 596 {bool strict: false}) { |
| 599 IterationStep wrapper(ClassElement cls) { | 597 IterationStep wrapper(ClassEntity cls) { |
| 600 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; | 598 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; |
| 601 } | 599 } |
| 602 | 600 |
| 603 return forEachSubtype(wrapper, mask, strict: strict) == IterationStep.STOP; | 601 return forEachSubtype(wrapper, mask, strict: strict) == IterationStep.STOP; |
| 604 } | 602 } |
| 605 | 603 |
| 606 /// Applies [f] to each subtype of [cls] matching the criteria specified by | 604 /// Applies [f] to each subtype of [cls] matching the criteria specified by |
| 607 /// [mask] and [strict]. | 605 /// [mask] and [strict]. |
| 608 /// | 606 /// |
| 609 /// [f] is a applied to subtypes if their instantiation properties intersect | 607 /// [f] is a applied to subtypes if their instantiation properties intersect |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 if (!added) { | 677 if (!added) { |
| 680 newSubtypes.add(subtype); | 678 newSubtypes.add(subtype); |
| 681 } | 679 } |
| 682 _subtypes = newSubtypes; | 680 _subtypes = newSubtypes; |
| 683 } | 681 } |
| 684 } | 682 } |
| 685 | 683 |
| 686 /// Returns the most specific subtype of [cls] (including [cls]) that is | 684 /// Returns the most specific subtype of [cls] (including [cls]) that is |
| 687 /// directly instantiated or a superclass of all directly instantiated | 685 /// directly instantiated or a superclass of all directly instantiated |
| 688 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. | 686 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. |
| 689 ClassElement getLubOfInstantiatedSubtypes() { | 687 ClassEntity getLubOfInstantiatedSubtypes() { |
| 690 if (_leastUpperInstantiatedSubtype == null) { | 688 if (_leastUpperInstantiatedSubtype == null) { |
| 691 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); | 689 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); |
| 692 } | 690 } |
| 693 return _leastUpperInstantiatedSubtype; | 691 return _leastUpperInstantiatedSubtype; |
| 694 } | 692 } |
| 695 | 693 |
| 696 ClassElement _computeLeastUpperInstantiatedSubtype() { | 694 ClassEntity _computeLeastUpperInstantiatedSubtype() { |
| 697 if (node.isExplicitlyInstantiated) { | 695 if (node.isExplicitlyInstantiated) { |
| 698 return cls; | 696 return cls; |
| 699 } | 697 } |
| 700 if (_subtypes == null) { | 698 if (_subtypes == null) { |
| 701 return node.getLubOfInstantiatedSubclasses(); | 699 return node.getLubOfInstantiatedSubclasses(); |
| 702 } | 700 } |
| 703 ClassHierarchyNode subtype; | 701 ClassHierarchyNode subtype; |
| 704 if (node.isInstantiated) { | 702 if (node.isInstantiated) { |
| 705 subtype = node; | 703 subtype = node; |
| 706 } | 704 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 729 node.printOn(sb, ' '); | 727 node.printOn(sb, ' '); |
| 730 sb.write('\n'); | 728 sb.write('\n'); |
| 731 } | 729 } |
| 732 } | 730 } |
| 733 sb.write(']'); | 731 sb.write(']'); |
| 734 return sb.toString(); | 732 return sb.toString(); |
| 735 } | 733 } |
| 736 } | 734 } |
| 737 | 735 |
| 738 /// Iterable for subclasses of a [ClassHierarchyNode]. | 736 /// Iterable for subclasses of a [ClassHierarchyNode]. |
| 739 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { | 737 class ClassHierarchyNodeIterable extends IterableBase<ClassEntity> { |
| 740 final ClassHierarchyNode root; | 738 final ClassHierarchyNode root; |
| 741 final EnumSet<Instantiation> mask; | 739 final EnumSet<Instantiation> mask; |
| 742 final bool includeRoot; | 740 final bool includeRoot; |
| 743 | 741 |
| 744 ClassHierarchyNodeIterable(this.root, this.mask, {this.includeRoot: true}) { | 742 ClassHierarchyNodeIterable(this.root, this.mask, {this.includeRoot: true}) { |
| 745 if (root == null) throw new StateError("No root for iterable."); | 743 if (root == null) throw new StateError("No root for iterable."); |
| 746 } | 744 } |
| 747 | 745 |
| 748 @override | 746 @override |
| 749 Iterator<ClassElement> get iterator { | 747 Iterator<ClassEntity> get iterator { |
| 750 return new ClassHierarchyNodeIterator(this); | 748 return new ClassHierarchyNodeIterator(this); |
| 751 } | 749 } |
| 752 } | 750 } |
| 753 | 751 |
| 754 /// Iterator for subclasses of a [ClassHierarchyNode]. | 752 /// Iterator for subclasses of a [ClassHierarchyNode]. |
| 755 /// | 753 /// |
| 756 /// Classes are returned in pre-order DFS fashion. | 754 /// Classes are returned in pre-order DFS fashion. |
| 757 class ClassHierarchyNodeIterator implements Iterator<ClassElement> { | 755 class ClassHierarchyNodeIterator implements Iterator<ClassEntity> { |
| 758 final ClassHierarchyNodeIterable iterable; | 756 final ClassHierarchyNodeIterable iterable; |
| 759 | 757 |
| 760 /// The class node holding the [current] class. | 758 /// The class node holding the [current] class. |
| 761 /// | 759 /// |
| 762 /// This is `null` before the first call to [moveNext] and at the end of | 760 /// This is `null` before the first call to [moveNext] and at the end of |
| 763 /// iteration, i.e. after [moveNext] has returned `false`. | 761 /// iteration, i.e. after [moveNext] has returned `false`. |
| 764 ClassHierarchyNode currentNode; | 762 ClassHierarchyNode currentNode; |
| 765 | 763 |
| 766 /// Stack of pending class nodes. | 764 /// Stack of pending class nodes. |
| 767 /// | 765 /// |
| 768 /// This is `null` before the first call to [moveNext]. | 766 /// This is `null` before the first call to [moveNext]. |
| 769 Link<ClassHierarchyNode> stack; | 767 Link<ClassHierarchyNode> stack; |
| 770 | 768 |
| 771 ClassHierarchyNodeIterator(this.iterable); | 769 ClassHierarchyNodeIterator(this.iterable); |
| 772 | 770 |
| 773 ClassHierarchyNode get root => iterable.root; | 771 ClassHierarchyNode get root => iterable.root; |
| 774 | 772 |
| 775 bool get includeRoot => iterable.includeRoot; | 773 bool get includeRoot => iterable.includeRoot; |
| 776 | 774 |
| 777 EnumSet<Instantiation> get mask => iterable.mask; | 775 EnumSet<Instantiation> get mask => iterable.mask; |
| 778 | 776 |
| 779 bool get includeUninstantiated { | 777 bool get includeUninstantiated { |
| 780 return mask.contains(Instantiation.UNINSTANTIATED); | 778 return mask.contains(Instantiation.UNINSTANTIATED); |
| 781 } | 779 } |
| 782 | 780 |
| 783 @override | 781 @override |
| 784 ClassElement get current { | 782 ClassEntity get current { |
| 785 return currentNode != null ? currentNode.cls : null; | 783 return currentNode != null ? currentNode.cls : null; |
| 786 } | 784 } |
| 787 | 785 |
| 788 @override | 786 @override |
| 789 bool moveNext() { | 787 bool moveNext() { |
| 790 if (stack == null) { | 788 if (stack == null) { |
| 791 // First call to moveNext | 789 // First call to moveNext |
| 792 stack = const Link<ClassHierarchyNode>().prepend(root); | 790 stack = const Link<ClassHierarchyNode>().prepend(root); |
| 793 return _findNext(); | 791 return _findNext(); |
| 794 } else { | 792 } else { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 } | 824 } |
| 827 | 825 |
| 828 /// Returns `true` if the class of [node] is a valid result for this iterator. | 826 /// Returns `true` if the class of [node] is a valid result for this iterator. |
| 829 bool _isValid(ClassHierarchyNode node) { | 827 bool _isValid(ClassHierarchyNode node) { |
| 830 if (!includeRoot && node == root) return false; | 828 if (!includeRoot && node == root) return false; |
| 831 return mask.intersects(node._mask); | 829 return mask.intersects(node._mask); |
| 832 } | 830 } |
| 833 } | 831 } |
| 834 | 832 |
| 835 /// Iterable for the subtypes in a [ClassSet]. | 833 /// Iterable for the subtypes in a [ClassSet]. |
| 836 class SubtypesIterable extends IterableBase<ClassElement> { | 834 class SubtypesIterable extends IterableBase<ClassEntity> { |
| 837 final ClassSet subtypeSet; | 835 final ClassSet subtypeSet; |
| 838 final EnumSet<Instantiation> mask; | 836 final EnumSet<Instantiation> mask; |
| 839 final bool includeRoot; | 837 final bool includeRoot; |
| 840 | 838 |
| 841 SubtypesIterable.SubtypesIterator(this.subtypeSet, this.mask, | 839 SubtypesIterable.SubtypesIterator(this.subtypeSet, this.mask, |
| 842 {this.includeRoot: true}); | 840 {this.includeRoot: true}); |
| 843 | 841 |
| 844 @override | 842 @override |
| 845 Iterator<ClassElement> get iterator => new SubtypesIterator(this); | 843 Iterator<ClassEntity> get iterator => new SubtypesIterator(this); |
| 846 } | 844 } |
| 847 | 845 |
| 848 /// Iterator for the subtypes in a [ClassSet]. | 846 /// Iterator for the subtypes in a [ClassSet]. |
| 849 class SubtypesIterator extends Iterator<ClassElement> { | 847 class SubtypesIterator extends Iterator<ClassEntity> { |
| 850 final SubtypesIterable iterable; | 848 final SubtypesIterable iterable; |
| 851 Iterator<ClassElement> elements; | 849 Iterator<ClassEntity> elements; |
| 852 Iterator<ClassHierarchyNode> hierarchyNodes; | 850 Iterator<ClassHierarchyNode> hierarchyNodes; |
| 853 | 851 |
| 854 SubtypesIterator(this.iterable); | 852 SubtypesIterator(this.iterable); |
| 855 | 853 |
| 856 bool get includeRoot => iterable.includeRoot; | 854 bool get includeRoot => iterable.includeRoot; |
| 857 | 855 |
| 858 EnumSet<Instantiation> get mask => iterable.mask; | 856 EnumSet<Instantiation> get mask => iterable.mask; |
| 859 | 857 |
| 860 @override | 858 @override |
| 861 ClassElement get current { | 859 ClassEntity get current { |
| 862 if (elements != null) { | 860 if (elements != null) { |
| 863 return elements.current; | 861 return elements.current; |
| 864 } | 862 } |
| 865 return null; | 863 return null; |
| 866 } | 864 } |
| 867 | 865 |
| 868 @override | 866 @override |
| 869 bool moveNext() { | 867 bool moveNext() { |
| 870 if (elements == null && hierarchyNodes == null) { | 868 if (elements == null && hierarchyNodes == null) { |
| 871 // Initial state. Iterate through subclasses. | 869 // Initial state. Iterate through subclasses. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 900 /// Iteration stops immediately. | 898 /// Iteration stops immediately. |
| 901 STOP, | 899 STOP, |
| 902 | 900 |
| 903 /// Iteration skips the subclasses of the current class. | 901 /// Iteration skips the subclasses of the current class. |
| 904 SKIP_SUBCLASSES, | 902 SKIP_SUBCLASSES, |
| 905 } | 903 } |
| 906 | 904 |
| 907 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] | 905 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] |
| 908 /// and [ClassSet]. The return value controls the continued iteration. If `null` | 906 /// and [ClassSet]. The return value controls the continued iteration. If `null` |
| 909 /// is returned, iteration continues to the end. | 907 /// is returned, iteration continues to the end. |
| 910 typedef IterationStep ForEachFunction(ClassElement cls); | 908 typedef IterationStep ForEachFunction(ClassEntity cls); |
| OLD | NEW |