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 |