Chromium Code Reviews| 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 |