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