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> ROOT_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. |
Siggi Cherem (dart-lang)
2016/10/27 13:22:07
it would be good to add here the definition of "ab
Johnni Winther
2016/11/01 11:26:34
Done.
| |
116 } | 124 /// |
Siggi Cherem (dart-lang)
2016/10/27 13:22:07
nit: delete line
Johnni Winther
2016/11/01 11:26:35
Done.
| |
117 } else { | 125 bool get isAbstractlyInstantiated => |
118 _mask.remove(Instantiation.DIRECTLY_INSTANTIATED); | 126 _mask.contains(Instantiation.ABSTRACTLY_INSTANTIATED); |
119 if (_mask.isEmpty) { | 127 |
120 _mask.add(Instantiation.UNINSTANTIATED); | 128 void set isAbstractlyInstantiated(bool value) { |
121 } | 129 if (value != isAbstractlyInstantiated) { |
122 while (parent != null) { | 130 _updateParentInstantiatedSubclassCount( |
123 parent._updateInstantiatedSubclassCount(-1); | 131 Instantiation.ABSTRACTLY_INSTANTIATED, |
124 parent = parent.parentNode; | 132 add: value); |
125 } | 133 } |
134 } | |
135 | |
136 /// `true` if [cls] is either directly or abstactly instantiated. | |
137 bool get isRootInstantiated => | |
Siggi Cherem (dart-lang)
2016/10/27 13:22:07
I'm trying to think of other names for this - root
Johnni Winther
2016/11/01 11:26:35
isExplicitlyInstantiated it is!
| |
138 isDirectlyInstantiated || isAbstractlyInstantiated; | |
139 | |
140 void _updateParentInstantiatedSubclassCount(Instantiation instantiation, | |
141 {bool add}) { | |
142 ClassHierarchyNode parent = parentNode; | |
143 if (add) { | |
144 _mask.remove(Instantiation.UNINSTANTIATED); | |
145 _mask.add(instantiation); | |
146 while (parent != null) { | |
147 parent._updateInstantiatedSubclassCount(1); | |
148 parent = parent.parentNode; | |
149 } | |
150 } else { | |
151 _mask.remove(instantiation); | |
152 if (_mask.isEmpty) { | |
153 _mask.add(Instantiation.UNINSTANTIATED); | |
154 } | |
155 while (parent != null) { | |
156 parent._updateInstantiatedSubclassCount(-1); | |
157 parent = parent.parentNode; | |
126 } | 158 } |
127 } | 159 } |
128 } | 160 } |
129 | 161 |
130 /// `true` if [cls] has been instantiated through subclasses. | 162 /// `true` if [cls] has been instantiated through subclasses. |
131 /// | 163 /// |
132 /// For instance `A` and `B` but _not_ `C` in: | 164 /// For instance `A` and `B` but _not_ `C` in: |
133 /// class A {} | 165 /// class A {} |
134 /// class B extends A {} | 166 /// class B extends A {} |
135 /// class C extends B {} | 167 /// 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]. | 213 /// This means that [other] is a subclass of [cls]. |
182 bool contains(ClassElement other) { | 214 bool contains(ClassElement other) { |
183 while (other != null) { | 215 while (other != null) { |
184 if (cls == other) return true; | 216 if (cls == other) return true; |
185 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; | 217 if (cls.hierarchyDepth >= other.hierarchyDepth) return false; |
186 other = other.superclass; | 218 other = other.superclass; |
187 } | 219 } |
188 return false; | 220 return false; |
189 } | 221 } |
190 | 222 |
191 /// `true` if [cls] has been directly or indirectly instantiated. | 223 /// `true` if [cls] has been directly, indirectly, or abstractly instantiated. |
192 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; | 224 bool get isInstantiated => isRootInstantiated || isIndirectlyInstantiated; |
193 | 225 |
194 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 226 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
195 /// | 227 /// |
196 /// Subclasses are included if their instantiation properties intersect with | 228 /// Subclasses are included if their instantiation properties intersect with |
197 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 229 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
198 /// `true`, [cls] itself is _not_ returned. | 230 /// `true`, [cls] itself is _not_ returned. |
199 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, | 231 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, |
200 {bool strict: false}) { | 232 {bool strict: false}) { |
201 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); | 233 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); |
202 } | 234 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 ClassElement getLubOfInstantiatedSubclasses() { | 295 ClassElement getLubOfInstantiatedSubclasses() { |
264 if (!isInstantiated) return null; | 296 if (!isInstantiated) return null; |
265 if (_leastUpperInstantiatedSubclass == null) { | 297 if (_leastUpperInstantiatedSubclass == null) { |
266 _leastUpperInstantiatedSubclass = | 298 _leastUpperInstantiatedSubclass = |
267 _computeLeastUpperInstantiatedSubclass(); | 299 _computeLeastUpperInstantiatedSubclass(); |
268 } | 300 } |
269 return _leastUpperInstantiatedSubclass; | 301 return _leastUpperInstantiatedSubclass; |
270 } | 302 } |
271 | 303 |
272 ClassElement _computeLeastUpperInstantiatedSubclass() { | 304 ClassElement _computeLeastUpperInstantiatedSubclass() { |
273 if (isDirectlyInstantiated) { | 305 if (isRootInstantiated) { |
274 return cls; | 306 return cls; |
275 } | 307 } |
308 if (!isInstantiated) { | |
309 return null; | |
310 } | |
276 ClassHierarchyNode subclass; | 311 ClassHierarchyNode subclass; |
277 for (Link<ClassHierarchyNode> link = _directSubclasses; | 312 for (Link<ClassHierarchyNode> link = _directSubclasses; |
278 !link.isEmpty; | 313 !link.isEmpty; |
279 link = link.tail) { | 314 link = link.tail) { |
280 if (link.head.isInstantiated) { | 315 if (link.head.isInstantiated) { |
281 if (subclass == null) { | 316 if (subclass == null) { |
282 subclass = link.head; | 317 subclass = link.head; |
283 } else { | 318 } else { |
284 return cls; | 319 return cls; |
285 } | 320 } |
(...skipping 18 matching lines...) Expand all Loading... | |
304 if (cls.isAbstract) { | 339 if (cls.isAbstract) { |
305 sb.write('abstract '); | 340 sb.write('abstract '); |
306 } | 341 } |
307 sb.write('class ${cls.name}:'); | 342 sb.write('class ${cls.name}:'); |
308 if (isDirectlyInstantiated) { | 343 if (isDirectlyInstantiated) { |
309 sb.write(' directly'); | 344 sb.write(' directly'); |
310 } | 345 } |
311 if (isIndirectlyInstantiated) { | 346 if (isIndirectlyInstantiated) { |
312 sb.write(' indirectly'); | 347 sb.write(' indirectly'); |
313 } | 348 } |
349 if (isAbstractlyInstantiated) { | |
350 sb.write(' abstractly'); | |
351 } | |
314 sb.write(' ['); | 352 sb.write(' ['); |
315 if (_directSubclasses.isEmpty) { | 353 if (_directSubclasses.isEmpty) { |
316 sb.write(']'); | 354 sb.write(']'); |
317 } else { | 355 } else { |
318 var subclasses = _directSubclasses; | 356 var subclasses = _directSubclasses; |
319 if (sorted) { | 357 if (sorted) { |
320 subclasses = _directSubclasses.toList() | 358 subclasses = _directSubclasses.toList() |
321 ..sort((a, b) { | 359 ..sort((a, b) { |
322 return a.cls.name.compareTo(b.cls.name); | 360 return a.cls.name.compareTo(b.cls.name); |
323 }); | 361 }); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 | 470 |
433 ClassSet(this.node); | 471 ClassSet(this.node); |
434 | 472 |
435 ClassElement get cls => node.cls; | 473 ClassElement get cls => node.cls; |
436 | 474 |
437 /// Returns the number of directly instantiated subtypes of [cls]. | 475 /// Returns the number of directly instantiated subtypes of [cls]. |
438 int get instantiatedSubtypeCount { | 476 int get instantiatedSubtypeCount { |
439 int count = node.instantiatedSubclassCount; | 477 int count = node.instantiatedSubclassCount; |
440 if (_subtypes != null) { | 478 if (_subtypes != null) { |
441 for (ClassHierarchyNode subtypeNode in _subtypes) { | 479 for (ClassHierarchyNode subtypeNode in _subtypes) { |
442 if (subtypeNode.isDirectlyInstantiated) { | 480 if (subtypeNode.isDirectlyInstantiated || |
Siggi Cherem (dart-lang)
2016/10/27 13:22:07
can we use isRootInstantiated here too?
Johnni Winther
2016/11/01 11:26:35
Done.
| |
481 subtypeNode.isAbstractlyInstantiated) { | |
443 count++; | 482 count++; |
444 } | 483 } |
445 count += subtypeNode.instantiatedSubclassCount; | 484 count += subtypeNode.instantiatedSubclassCount; |
446 } | 485 } |
447 } | 486 } |
448 return count; | 487 return count; |
449 } | 488 } |
450 | 489 |
451 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of | 490 /// Returns `true` if all instantiated subtypes of [cls] are subclasses of |
452 /// [cls]. | 491 /// [cls]. |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
640 /// directly instantiated or a superclass of all directly instantiated | 679 /// directly instantiated or a superclass of all directly instantiated |
641 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. | 680 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. |
642 ClassElement getLubOfInstantiatedSubtypes() { | 681 ClassElement getLubOfInstantiatedSubtypes() { |
643 if (_leastUpperInstantiatedSubtype == null) { | 682 if (_leastUpperInstantiatedSubtype == null) { |
644 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); | 683 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); |
645 } | 684 } |
646 return _leastUpperInstantiatedSubtype; | 685 return _leastUpperInstantiatedSubtype; |
647 } | 686 } |
648 | 687 |
649 ClassElement _computeLeastUpperInstantiatedSubtype() { | 688 ClassElement _computeLeastUpperInstantiatedSubtype() { |
650 if (node.isDirectlyInstantiated) { | 689 if (node.isRootInstantiated) { |
651 return cls; | 690 return cls; |
652 } | 691 } |
653 if (_subtypes == null) { | 692 if (_subtypes == null) { |
654 return node.getLubOfInstantiatedSubclasses(); | 693 return node.getLubOfInstantiatedSubclasses(); |
655 } | 694 } |
656 ClassHierarchyNode subtype; | 695 ClassHierarchyNode subtype; |
657 if (node.isInstantiated) { | 696 if (node.isInstantiated) { |
658 subtype = node; | 697 subtype = node; |
659 } | 698 } |
660 for (ClassHierarchyNode subnode in _subtypes) { | 699 for (ClassHierarchyNode subnode in _subtypes) { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
854 STOP, | 893 STOP, |
855 | 894 |
856 /// Iteration skips the subclasses of the current class. | 895 /// Iteration skips the subclasses of the current class. |
857 SKIP_SUBCLASSES, | 896 SKIP_SUBCLASSES, |
858 } | 897 } |
859 | 898 |
860 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] | 899 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] |
861 /// and [ClassSet]. The return value controls the continued iteration. If `null` | 900 /// and [ClassSet]. The return value controls the continued iteration. If `null` |
862 /// is returned, iteration continues to the end. | 901 /// is returned, iteration continues to the end. |
863 typedef IterationStep ForEachFunction(ClassElement cls); | 902 typedef IterationStep ForEachFunction(ClassElement cls); |
OLD | NEW |