| 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 | 7 import 'dart:collection' show IterableBase; |
| 8 IterableBase; | 8 import '../elements/elements.dart' show ClassElement; |
| 9 import '../elements/elements.dart' show | 9 import '../util/enumset.dart' show EnumSet; |
| 10 ClassElement; | 10 import '../util/util.dart' show Link; |
| 11 import '../util/enumset.dart' show | |
| 12 EnumSet; | |
| 13 import '../util/util.dart' show | |
| 14 Link; | |
| 15 | 11 |
| 16 /// Enum for the different kinds of instantiation of a class. | 12 /// Enum for the different kinds of instantiation of a class. |
| 17 enum Instantiation { | 13 enum Instantiation { |
| 18 UNINSTANTIATED, | 14 UNINSTANTIATED, |
| 19 DIRECTLY_INSTANTIATED, | 15 DIRECTLY_INSTANTIATED, |
| 20 INDIRECTLY_INSTANTIATED, | 16 INDIRECTLY_INSTANTIATED, |
| 21 } | 17 } |
| 22 | 18 |
| 23 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. | 19 /// Node for [cls] in a tree forming the subclass relation of [ClassElement]s. |
| 24 /// | 20 /// |
| (...skipping 18 matching lines...) Expand all Loading... |
| 43 /// | | 39 /// | |
| 44 /// D | 40 /// D |
| 45 /// | | 41 /// | |
| 46 /// E | 42 /// E |
| 47 /// | 43 /// |
| 48 class ClassHierarchyNode { | 44 class ClassHierarchyNode { |
| 49 /// Enum set for selecting instantiated classes in | 45 /// Enum set for selecting instantiated classes in |
| 50 /// [ClassHierarchyNode.subclassesByMask], | 46 /// [ClassHierarchyNode.subclassesByMask], |
| 51 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 47 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 52 static final EnumSet<Instantiation> INSTANTIATED = | 48 static final EnumSet<Instantiation> INSTANTIATED = |
| 53 new EnumSet<Instantiation>.fromValues( | 49 new EnumSet<Instantiation>.fromValues(const <Instantiation>[ |
| 54 const <Instantiation>[ | 50 Instantiation.DIRECTLY_INSTANTIATED, |
| 55 Instantiation.DIRECTLY_INSTANTIATED, | 51 Instantiation.INDIRECTLY_INSTANTIATED |
| 56 Instantiation.INDIRECTLY_INSTANTIATED], | 52 ], fixed: true); |
| 57 fixed: true); | |
| 58 | 53 |
| 59 /// Enum set for selecting directly instantiated classes in | 54 /// Enum set for selecting directly instantiated classes in |
| 60 /// [ClassHierarchyNode.subclassesByMask], | 55 /// [ClassHierarchyNode.subclassesByMask], |
| 61 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 56 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 62 static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = | 57 static final EnumSet<Instantiation> DIRECTLY_INSTANTIATED = |
| 63 new EnumSet<Instantiation>.fromValues( | 58 new EnumSet<Instantiation>.fromValues( |
| 64 const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], | 59 const <Instantiation>[Instantiation.DIRECTLY_INSTANTIATED], |
| 65 fixed: true); | 60 fixed: true); |
| 66 | 61 |
| 67 /// Enum set for selecting all classes in | 62 /// Enum set for selecting all classes in |
| 68 /// [ClassHierarchyNode.subclassesByMask], | 63 /// [ClassHierarchyNode.subclassesByMask], |
| 69 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 64 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 70 static final EnumSet<Instantiation> ALL = | 65 static final EnumSet<Instantiation> ALL = |
| 71 new EnumSet<Instantiation>.fromValues( | 66 new EnumSet<Instantiation>.fromValues(Instantiation.values, fixed: true); |
| 72 Instantiation.values, | |
| 73 fixed: true); | |
| 74 | 67 |
| 75 /// Creates an enum set for selecting the returned classes in | 68 /// Creates an enum set for selecting the returned classes in |
| 76 /// [ClassHierarchyNode.subclassesByMask], | 69 /// [ClassHierarchyNode.subclassesByMask], |
| 77 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. | 70 /// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask]. |
| 78 static EnumSet<Instantiation> createMask( | 71 static EnumSet<Instantiation> createMask( |
| 79 {bool includeDirectlyInstantiated: true, | 72 {bool includeDirectlyInstantiated: true, |
| 80 bool includeIndirectlyInstantiated: true, | 73 bool includeIndirectlyInstantiated: true, |
| 81 bool includeUninstantiated: true}) { | 74 bool includeUninstantiated: true}) { |
| 82 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); | 75 EnumSet<Instantiation> mask = new EnumSet<Instantiation>(); |
| 83 if (includeDirectlyInstantiated) { | 76 if (includeDirectlyInstantiated) { |
| 84 mask.add(Instantiation.DIRECTLY_INSTANTIATED); | 77 mask.add(Instantiation.DIRECTLY_INSTANTIATED); |
| 85 } | 78 } |
| 86 if (includeIndirectlyInstantiated) { | 79 if (includeIndirectlyInstantiated) { |
| 87 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); | 80 mask.add(Instantiation.INDIRECTLY_INSTANTIATED); |
| 88 } | 81 } |
| 89 if (includeUninstantiated) { | 82 if (includeUninstantiated) { |
| 90 mask.add(Instantiation.UNINSTANTIATED); | 83 mask.add(Instantiation.UNINSTANTIATED); |
| 91 } | 84 } |
| 92 return mask; | 85 return mask; |
| 93 } | 86 } |
| 94 | 87 |
| 95 final ClassHierarchyNode parentNode; | 88 final ClassHierarchyNode parentNode; |
| 96 final ClassElement cls; | 89 final ClassElement cls; |
| 97 final EnumSet<Instantiation> _mask = | 90 final EnumSet<Instantiation> _mask = new EnumSet<Instantiation>.fromValues( |
| 98 new EnumSet<Instantiation>.fromValues( | 91 const <Instantiation>[Instantiation.UNINSTANTIATED]); |
| 99 const <Instantiation>[Instantiation.UNINSTANTIATED]); | |
| 100 | 92 |
| 101 ClassElement _leastUpperInstantiatedSubclass; | 93 ClassElement _leastUpperInstantiatedSubclass; |
| 102 int _instantiatedSubclassCount = 0; | 94 int _instantiatedSubclassCount = 0; |
| 103 | 95 |
| 104 /// `true` if [cls] has been directly instantiated. | 96 /// `true` if [cls] has been directly instantiated. |
| 105 /// | 97 /// |
| 106 /// For instance `C` but _not_ `B` in: | 98 /// For instance `C` but _not_ `B` in: |
| 107 /// class B {} | 99 /// class B {} |
| 108 /// class C extends B {} | 100 /// class C extends B {} |
| 109 /// main() => new C(); | 101 /// main() => new C(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 } | 188 } |
| 197 | 189 |
| 198 /// `true` if [cls] has been directly or indirectly instantiated. | 190 /// `true` if [cls] has been directly or indirectly instantiated. |
| 199 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; | 191 bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated; |
| 200 | 192 |
| 201 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 193 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 202 /// | 194 /// |
| 203 /// Subclasses are included if their instantiation properties intersect with | 195 /// Subclasses are included if their instantiation properties intersect with |
| 204 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 196 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 205 /// `true`, [cls] itself is _not_ returned. | 197 /// `true`, [cls] itself is _not_ returned. |
| 206 Iterable<ClassElement> subclassesByMask( | 198 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, |
| 207 EnumSet<Instantiation> mask, | |
| 208 {bool strict: false}) { | 199 {bool strict: false}) { |
| 209 return new ClassHierarchyNodeIterable( | 200 return new ClassHierarchyNodeIterable(this, mask, includeRoot: !strict); |
| 210 this, mask, includeRoot: !strict); | |
| 211 } | 201 } |
| 212 | 202 |
| 213 /// Applies [predicate] to each subclass of [cls] matching the criteria | 203 /// Applies [predicate] to each subclass of [cls] matching the criteria |
| 214 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 204 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 215 /// class, visitation is stopped immediately and the function returns `true`. | 205 /// class, visitation is stopped immediately and the function returns `true`. |
| 216 /// | 206 /// |
| 217 /// [predicate] is applied to subclasses if their instantiation properties | 207 /// [predicate] is applied to subclasses if their instantiation properties |
| 218 /// intersect with their corresponding [Instantiation] values in [mask]. If | 208 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 219 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 209 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 220 bool anySubclass( | 210 bool anySubclass( |
| 221 bool predicate(ClassElement cls), | 211 bool predicate(ClassElement cls), EnumSet<Instantiation> mask, |
| 222 EnumSet<Instantiation> mask, | |
| 223 {bool strict: false}) { | 212 {bool strict: false}) { |
| 224 | |
| 225 IterationStep wrapper(ClassElement cls) { | 213 IterationStep wrapper(ClassElement cls) { |
| 226 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; | 214 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; |
| 227 } | 215 } |
| 228 return forEachSubclass(wrapper, mask, strict: strict) == IterationStep.STOP; | 216 return forEachSubclass(wrapper, mask, strict: strict) == IterationStep.STOP; |
| 229 } | 217 } |
| 230 | 218 |
| 231 /// Applies [f] to each subclass of [cls] matching the criteria specified by | 219 /// Applies [f] to each subclass of [cls] matching the criteria specified by |
| 232 /// [mask] and [strict]. | 220 /// [mask] and [strict]. |
| 233 /// | 221 /// |
| 234 /// [f] is a applied to subclasses if their instantiation properties intersect | 222 /// [f] is a applied to subclasses if their instantiation properties intersect |
| 235 /// with their corresponding [Instantiation] values in [mask]. If [strict] is | 223 /// with their corresponding [Instantiation] values in [mask]. If [strict] is |
| 236 /// `true`, [f] is _not_ called on [cls] itself. | 224 /// `true`, [f] is _not_ called on [cls] itself. |
| 237 /// | 225 /// |
| 238 /// The visitation of subclasses can be cut short by the return value of [f]. | 226 /// The visitation of subclasses can be cut short by the return value of [f]. |
| 239 /// If [ForEach.STOP] is returned, no further classes are visited and the | 227 /// If [ForEach.STOP] is returned, no further classes are visited and the |
| 240 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the | 228 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the |
| 241 /// subclasses of the last visited class are skipped, but visitation | 229 /// subclasses of the last visited class are skipped, but visitation |
| 242 /// continues. The return value of the function is either [ForEach.STOP], if | 230 /// continues. The return value of the function is either [ForEach.STOP], if |
| 243 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to | 231 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to |
| 244 /// the end. | 232 /// the end. |
| 245 IterationStep forEachSubclass( | 233 IterationStep forEachSubclass(ForEachFunction f, EnumSet<Instantiation> mask, |
| 246 ForEachFunction f, | |
| 247 EnumSet<Instantiation> mask, | |
| 248 {bool strict: false}) { | 234 {bool strict: false}) { |
| 249 IterationStep nextStep; | 235 IterationStep nextStep; |
| 250 if (!strict && mask.intersects(_mask)) { | 236 if (!strict && mask.intersects(_mask)) { |
| 251 nextStep = f(cls); | 237 nextStep = f(cls); |
| 252 } | 238 } |
| 253 // Interpret `forEach == null` as `forEach == ForEach.CONTINUE`. | 239 // Interpret `forEach == null` as `forEach == ForEach.CONTINUE`. |
| 254 nextStep ??= IterationStep.CONTINUE; | 240 nextStep ??= IterationStep.CONTINUE; |
| 255 | 241 |
| 256 if (nextStep == IterationStep.CONTINUE) { | 242 if (nextStep == IterationStep.CONTINUE) { |
| 257 if (mask.contains(Instantiation.UNINSTANTIATED) || isInstantiated) { | 243 if (mask.contains(Instantiation.UNINSTANTIATED) || isInstantiated) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 280 } | 266 } |
| 281 return _leastUpperInstantiatedSubclass; | 267 return _leastUpperInstantiatedSubclass; |
| 282 } | 268 } |
| 283 | 269 |
| 284 ClassElement _computeLeastUpperInstantiatedSubclass() { | 270 ClassElement _computeLeastUpperInstantiatedSubclass() { |
| 285 if (isDirectlyInstantiated) { | 271 if (isDirectlyInstantiated) { |
| 286 return cls; | 272 return cls; |
| 287 } | 273 } |
| 288 ClassHierarchyNode subclass; | 274 ClassHierarchyNode subclass; |
| 289 for (Link<ClassHierarchyNode> link = _directSubclasses; | 275 for (Link<ClassHierarchyNode> link = _directSubclasses; |
| 290 !link.isEmpty; | 276 !link.isEmpty; |
| 291 link = link.tail) { | 277 link = link.tail) { |
| 292 if (link.head.isInstantiated) { | 278 if (link.head.isInstantiated) { |
| 293 if (subclass == null) { | 279 if (subclass == null) { |
| 294 subclass = link.head; | 280 subclass = link.head; |
| 295 } else { | 281 } else { |
| 296 return cls; | 282 return cls; |
| 297 } | 283 } |
| 298 } | 284 } |
| 299 } | 285 } |
| 300 if (subclass != null) { | 286 if (subclass != null) { |
| 301 return subclass.getLubOfInstantiatedSubclasses(); | 287 return subclass.getLubOfInstantiatedSubclasses(); |
| 302 } | 288 } |
| 303 return cls; | 289 return cls; |
| 304 } | 290 } |
| 305 | 291 |
| 306 void printOn(StringBuffer sb, String indentation, | 292 void printOn(StringBuffer sb, String indentation, |
| 307 {bool instantiatedOnly: false, | 293 {bool instantiatedOnly: false, |
| 308 bool sorted: true, | 294 bool sorted: true, |
| 309 ClassElement withRespectTo}) { | 295 ClassElement withRespectTo}) { |
| 310 | |
| 311 bool isRelatedTo(ClassElement subclass) { | 296 bool isRelatedTo(ClassElement subclass) { |
| 312 return subclass == withRespectTo || | 297 return subclass == withRespectTo || |
| 313 subclass.implementsInterface(withRespectTo); | 298 subclass.implementsInterface(withRespectTo); |
| 314 } | 299 } |
| 315 | 300 |
| 316 sb.write(indentation); | 301 sb.write(indentation); |
| 317 if (cls.isAbstract) { | 302 if (cls.isAbstract) { |
| 318 sb.write('abstract '); | 303 sb.write('abstract '); |
| 319 } | 304 } |
| 320 sb.write('class ${cls.name}:'); | 305 sb.write('class ${cls.name}:'); |
| 321 if (isDirectlyInstantiated) { | 306 if (isDirectlyInstantiated) { |
| 322 sb.write(' directly'); | 307 sb.write(' directly'); |
| 323 } | 308 } |
| 324 if (isIndirectlyInstantiated) { | 309 if (isIndirectlyInstantiated) { |
| 325 sb.write(' indirectly'); | 310 sb.write(' indirectly'); |
| 326 } | 311 } |
| 327 sb.write(' ['); | 312 sb.write(' ['); |
| 328 if (_directSubclasses.isEmpty) { | 313 if (_directSubclasses.isEmpty) { |
| 329 sb.write(']'); | 314 sb.write(']'); |
| 330 } else { | 315 } else { |
| 331 var subclasses = _directSubclasses; | 316 var subclasses = _directSubclasses; |
| 332 if (sorted) { | 317 if (sorted) { |
| 333 subclasses = _directSubclasses.toList()..sort((a, b) { | 318 subclasses = _directSubclasses.toList() |
| 334 return a.cls.name.compareTo(b.cls.name); | 319 ..sort((a, b) { |
| 335 }); | 320 return a.cls.name.compareTo(b.cls.name); |
| 321 }); |
| 336 } | 322 } |
| 337 bool needsComma = false; | 323 bool needsComma = false; |
| 338 for (ClassHierarchyNode child in subclasses) { | 324 for (ClassHierarchyNode child in subclasses) { |
| 339 if (instantiatedOnly && !child.isInstantiated) { | 325 if (instantiatedOnly && !child.isInstantiated) { |
| 340 continue; | 326 continue; |
| 341 } | 327 } |
| 342 if (withRespectTo != null && | 328 if (withRespectTo != null && |
| 343 !child.anySubclass(isRelatedTo, ClassHierarchyNode.ALL)) { | 329 !child.anySubclass(isRelatedTo, ClassHierarchyNode.ALL)) { |
| 344 continue; | 330 continue; |
| 345 } | 331 } |
| 346 if (needsComma) { | 332 if (needsComma) { |
| 347 sb.write(',\n'); | 333 sb.write(',\n'); |
| 348 } else { | 334 } else { |
| 349 sb.write('\n'); | 335 sb.write('\n'); |
| 350 } | 336 } |
| 351 child.printOn( | 337 child.printOn(sb, '$indentation ', |
| 352 sb, | |
| 353 '$indentation ', | |
| 354 instantiatedOnly: instantiatedOnly, | 338 instantiatedOnly: instantiatedOnly, |
| 355 sorted: sorted, | 339 sorted: sorted, |
| 356 withRespectTo: withRespectTo); | 340 withRespectTo: withRespectTo); |
| 357 needsComma = true; | 341 needsComma = true; |
| 358 } | 342 } |
| 359 if (needsComma) { | 343 if (needsComma) { |
| 360 sb.write('\n'); | 344 sb.write('\n'); |
| 361 sb.write('$indentation]'); | 345 sb.write('$indentation]'); |
| 362 } else { | 346 } else { |
| 363 sb.write(']'); | 347 sb.write(']'); |
| 364 } | 348 } |
| 365 } | 349 } |
| 366 } | 350 } |
| 367 | 351 |
| 368 String dump({String indentation: '', | 352 String dump( |
| 369 bool instantiatedOnly: false, | 353 {String indentation: '', |
| 370 ClassElement withRespectTo}) { | 354 bool instantiatedOnly: false, |
| 355 ClassElement withRespectTo}) { |
| 371 StringBuffer sb = new StringBuffer(); | 356 StringBuffer sb = new StringBuffer(); |
| 372 printOn(sb, indentation, | 357 printOn(sb, indentation, |
| 373 instantiatedOnly: instantiatedOnly, | 358 instantiatedOnly: instantiatedOnly, withRespectTo: withRespectTo); |
| 374 withRespectTo: withRespectTo); | |
| 375 return sb.toString(); | 359 return sb.toString(); |
| 376 } | 360 } |
| 377 | 361 |
| 378 String toString() => cls.toString(); | 362 String toString() => cls.toString(); |
| 379 } | 363 } |
| 380 | 364 |
| 381 /// Object holding the subclass and subtype relation for a single | 365 /// Object holding the subclass and subtype relation for a single |
| 382 /// [ClassElement]. | 366 /// [ClassElement]. |
| 383 /// | 367 /// |
| 384 /// The subclass relation for a class `C` is modelled through a reference to | 368 /// The subclass relation for a class `C` is modelled through a reference to |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 } | 457 } |
| 474 } | 458 } |
| 475 return true; | 459 return true; |
| 476 } | 460 } |
| 477 | 461 |
| 478 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 462 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
| 479 /// | 463 /// |
| 480 /// Subclasses are included if their instantiation properties intersect with | 464 /// Subclasses are included if their instantiation properties intersect with |
| 481 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 465 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 482 /// `true`, [cls] itself is _not_ returned. | 466 /// `true`, [cls] itself is _not_ returned. |
| 483 Iterable<ClassElement> subclassesByMask( | 467 Iterable<ClassElement> subclassesByMask(EnumSet<Instantiation> mask, |
| 484 EnumSet<Instantiation> mask, | |
| 485 {bool strict: false}) { | 468 {bool strict: false}) { |
| 486 return node.subclassesByMask(mask, strict: strict); | 469 return node.subclassesByMask(mask, strict: strict); |
| 487 } | 470 } |
| 488 | 471 |
| 489 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. | 472 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 490 /// | 473 /// |
| 491 /// The directly instantiated, indirectly instantiated and uninstantiated | 474 /// The directly instantiated, indirectly instantiated and uninstantiated |
| 492 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], | 475 /// subtypes of [cls] are returned if [includeDirectlyInstantiated], |
| 493 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, | 476 /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`, |
| 494 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. | 477 /// respectively. If [strict] is `true`, [cls] itself is _not_ returned. |
| 495 Iterable<ClassElement> subtypes( | 478 Iterable<ClassElement> subtypes( |
| 496 {bool includeDirectlyInstantiated: true, | 479 {bool includeDirectlyInstantiated: true, |
| 497 bool includeIndirectlyInstantiated: true, | 480 bool includeIndirectlyInstantiated: true, |
| 498 bool includeUninstantiated: true, | 481 bool includeUninstantiated: true, |
| 499 bool strict: false}) { | 482 bool strict: false}) { |
| 500 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( | 483 EnumSet<Instantiation> mask = ClassHierarchyNode.createMask( |
| 501 includeDirectlyInstantiated: includeDirectlyInstantiated, | 484 includeDirectlyInstantiated: includeDirectlyInstantiated, |
| 502 includeIndirectlyInstantiated:includeIndirectlyInstantiated, | 485 includeIndirectlyInstantiated: includeIndirectlyInstantiated, |
| 503 includeUninstantiated: includeUninstantiated); | 486 includeUninstantiated: includeUninstantiated); |
| 504 return subtypesByMask(mask, strict: strict); | 487 return subtypesByMask(mask, strict: strict); |
| 505 } | 488 } |
| 506 | 489 |
| 507 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. | 490 /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls]. |
| 508 /// | 491 /// |
| 509 /// Subtypes are included if their instantiation properties intersect with | 492 /// Subtypes are included if their instantiation properties intersect with |
| 510 /// their corresponding [Instantiation] values in [mask]. If [strict] is | 493 /// their corresponding [Instantiation] values in [mask]. If [strict] is |
| 511 /// `true`, [cls] itself is _not_ returned. | 494 /// `true`, [cls] itself is _not_ returned. |
| 512 Iterable<ClassElement> subtypesByMask( | 495 Iterable<ClassElement> subtypesByMask(EnumSet<Instantiation> mask, |
| 513 EnumSet<Instantiation> mask, | |
| 514 {bool strict: false}) { | 496 {bool strict: false}) { |
| 515 if (_subtypes == null) { | 497 if (_subtypes == null) { |
| 516 return node.subclassesByMask( | 498 return node.subclassesByMask(mask, strict: strict); |
| 517 mask, | |
| 518 strict: strict); | |
| 519 } | 499 } |
| 520 | 500 |
| 521 return new SubtypesIterable.SubtypesIterator(this, | 501 return new SubtypesIterable.SubtypesIterator(this, mask, |
| 522 mask, | |
| 523 includeRoot: !strict); | 502 includeRoot: !strict); |
| 524 } | 503 } |
| 525 | 504 |
| 526 /// Applies [predicate] to each subclass of [cls] matching the criteria | 505 /// Applies [predicate] to each subclass of [cls] matching the criteria |
| 527 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 506 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 528 /// class, visitation is stopped immediately and the function returns `true`. | 507 /// class, visitation is stopped immediately and the function returns `true`. |
| 529 /// | 508 /// |
| 530 /// [predicate] is applied to subclasses if their instantiation properties | 509 /// [predicate] is applied to subclasses if their instantiation properties |
| 531 /// intersect with their corresponding [Instantiation] values in [mask]. If | 510 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 532 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 511 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 533 bool anySubclass( | 512 bool anySubclass( |
| 534 bool predicate(ClassElement cls), | 513 bool predicate(ClassElement cls), EnumSet<Instantiation> mask, |
| 535 EnumSet<Instantiation> mask, | |
| 536 {bool strict: false}) { | 514 {bool strict: false}) { |
| 537 return node.anySubclass(predicate, mask, strict: strict); | 515 return node.anySubclass(predicate, mask, strict: strict); |
| 538 } | 516 } |
| 539 | 517 |
| 540 /// Applies [f] to each subclass of [cls] matching the criteria specified by | 518 /// Applies [f] to each subclass of [cls] matching the criteria specified by |
| 541 /// [mask] and [strict]. | 519 /// [mask] and [strict]. |
| 542 /// | 520 /// |
| 543 /// [f] is a applied to subclasses if their instantiation properties intersect | 521 /// [f] is a applied to subclasses if their instantiation properties intersect |
| 544 /// with their corresponding [Instantiation] values in [mask]. If [strict] is | 522 /// with their corresponding [Instantiation] values in [mask]. If [strict] is |
| 545 /// `true`, [f] is _not_ called on [cls] itself. | 523 /// `true`, [f] is _not_ called on [cls] itself. |
| 546 /// | 524 /// |
| 547 /// The visitation of subclasses can be cut short by the return value of [f]. | 525 /// The visitation of subclasses can be cut short by the return value of [f]. |
| 548 /// If [ForEach.STOP] is returned, no further classes are visited and the | 526 /// If [ForEach.STOP] is returned, no further classes are visited and the |
| 549 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the | 527 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the |
| 550 /// subclasses of the last visited class are skipped, but visitation | 528 /// subclasses of the last visited class are skipped, but visitation |
| 551 /// continues. The return value of the function is either [ForEach.STOP], if | 529 /// continues. The return value of the function is either [ForEach.STOP], if |
| 552 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to | 530 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to |
| 553 /// the end. | 531 /// the end. |
| 554 IterationStep forEachSubclass( | 532 IterationStep forEachSubclass(ForEachFunction f, EnumSet<Instantiation> mask, |
| 555 ForEachFunction f, | |
| 556 EnumSet<Instantiation> mask, | |
| 557 {bool strict: false}) { | 533 {bool strict: false}) { |
| 558 return node.forEachSubclass(f, mask, strict: strict); | 534 return node.forEachSubclass(f, mask, strict: strict); |
| 559 } | 535 } |
| 560 | 536 |
| 561 /// Applies [predicate] to each subtype of [cls] matching the criteria | 537 /// Applies [predicate] to each subtype of [cls] matching the criteria |
| 562 /// specified by [mask] and [strict]. If [predicate] returns `true` on a | 538 /// specified by [mask] and [strict]. If [predicate] returns `true` on a |
| 563 /// class, visitation is stopped immediately and the function returns `true`. | 539 /// class, visitation is stopped immediately and the function returns `true`. |
| 564 /// | 540 /// |
| 565 /// [predicate] is applied to subtypes if their instantiation properties | 541 /// [predicate] is applied to subtypes if their instantiation properties |
| 566 /// intersect with their corresponding [Instantiation] values in [mask]. If | 542 /// intersect with their corresponding [Instantiation] values in [mask]. If |
| 567 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. | 543 /// [strict] is `true`, [predicate] is _not_ called on [cls] itself. |
| 568 bool anySubtype( | 544 bool anySubtype(bool predicate(ClassElement cls), EnumSet<Instantiation> mask, |
| 569 bool predicate(ClassElement cls), | |
| 570 EnumSet<Instantiation> mask, | |
| 571 {bool strict: false}) { | 545 {bool strict: false}) { |
| 572 | |
| 573 IterationStep wrapper(ClassElement cls) { | 546 IterationStep wrapper(ClassElement cls) { |
| 574 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; | 547 return predicate(cls) ? IterationStep.STOP : IterationStep.CONTINUE; |
| 575 } | 548 } |
| 576 return forEachSubtype(wrapper, mask, strict: strict) == IterationStep.STOP; | 549 return forEachSubtype(wrapper, mask, strict: strict) == IterationStep.STOP; |
| 577 } | 550 } |
| 578 | 551 |
| 579 /// Applies [f] to each subtype of [cls] matching the criteria specified by | 552 /// Applies [f] to each subtype of [cls] matching the criteria specified by |
| 580 /// [mask] and [strict]. | 553 /// [mask] and [strict]. |
| 581 /// | 554 /// |
| 582 /// [f] is a applied to subtypes if their instantiation properties intersect | 555 /// [f] is a applied to subtypes if their instantiation properties intersect |
| 583 /// with their corresponding [Instantiation] values in [mask]. If [strict] is | 556 /// with their corresponding [Instantiation] values in [mask]. If [strict] is |
| 584 /// `true`, [f] is _not_ called on [cls] itself. | 557 /// `true`, [f] is _not_ called on [cls] itself. |
| 585 /// | 558 /// |
| 586 /// The visitation of subtypes can be cut short by the return value of [f]. | 559 /// The visitation of subtypes can be cut short by the return value of [f]. |
| 587 /// If [ForEach.STOP] is returned, no further classes are visited and the | 560 /// If [ForEach.STOP] is returned, no further classes are visited and the |
| 588 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the | 561 /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the |
| 589 /// subclasses of the last visited class are skipped, but visitation | 562 /// subclasses of the last visited class are skipped, but visitation |
| 590 /// continues. The return value of the function is either [ForEach.STOP], if | 563 /// continues. The return value of the function is either [ForEach.STOP], if |
| 591 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to | 564 /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to |
| 592 /// the end. | 565 /// the end. |
| 593 IterationStep forEachSubtype( | 566 IterationStep forEachSubtype(ForEachFunction f, EnumSet<Instantiation> mask, |
| 594 ForEachFunction f, | |
| 595 EnumSet<Instantiation> mask, | |
| 596 {bool strict: false}) { | 567 {bool strict: false}) { |
| 597 IterationStep nextStep = | 568 IterationStep nextStep = |
| 598 node.forEachSubclass(f, mask, strict: strict) ?? IterationStep.CONTINUE; | 569 node.forEachSubclass(f, mask, strict: strict) ?? IterationStep.CONTINUE; |
| 599 if (nextStep == IterationStep.CONTINUE && _subtypes != null) { | 570 if (nextStep == IterationStep.CONTINUE && _subtypes != null) { |
| 600 for (ClassHierarchyNode subclass in _subtypes) { | 571 for (ClassHierarchyNode subclass in _subtypes) { |
| 601 IterationStep subForEach = subclass.forEachSubclass(f, mask); | 572 IterationStep subForEach = subclass.forEachSubclass(f, mask); |
| 602 if (subForEach == IterationStep.STOP) { | 573 if (subForEach == IterationStep.STOP) { |
| 603 return subForEach; | 574 return subForEach; |
| 604 } | 575 } |
| 605 } | 576 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 return sb.toString(); | 680 return sb.toString(); |
| 710 } | 681 } |
| 711 } | 682 } |
| 712 | 683 |
| 713 /// Iterable for subclasses of a [ClassHierarchyNode]. | 684 /// Iterable for subclasses of a [ClassHierarchyNode]. |
| 714 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { | 685 class ClassHierarchyNodeIterable extends IterableBase<ClassElement> { |
| 715 final ClassHierarchyNode root; | 686 final ClassHierarchyNode root; |
| 716 final EnumSet<Instantiation> mask; | 687 final EnumSet<Instantiation> mask; |
| 717 final bool includeRoot; | 688 final bool includeRoot; |
| 718 | 689 |
| 719 ClassHierarchyNodeIterable( | 690 ClassHierarchyNodeIterable(this.root, this.mask, {this.includeRoot: true}) { |
| 720 this.root, | |
| 721 this.mask, | |
| 722 {this.includeRoot: true}) { | |
| 723 if (root == null) throw new StateError("No root for iterable."); | 691 if (root == null) throw new StateError("No root for iterable."); |
| 724 } | 692 } |
| 725 | 693 |
| 726 @override | 694 @override |
| 727 Iterator<ClassElement> get iterator { | 695 Iterator<ClassElement> get iterator { |
| 728 return new ClassHierarchyNodeIterator(this); | 696 return new ClassHierarchyNodeIterator(this); |
| 729 } | 697 } |
| 730 } | 698 } |
| 731 | 699 |
| 732 /// Iterator for subclasses of a [ClassHierarchyNode]. | 700 /// Iterator for subclasses of a [ClassHierarchyNode]. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 return false; | 754 return false; |
| 787 } | 755 } |
| 788 currentNode = stack.head; | 756 currentNode = stack.head; |
| 789 stack = stack.tail; | 757 stack = stack.tail; |
| 790 if (!includeUninstantiated && !currentNode.isInstantiated) { | 758 if (!includeUninstantiated && !currentNode.isInstantiated) { |
| 791 // We're only iterating instantiated classes so there is no use in | 759 // We're only iterating instantiated classes so there is no use in |
| 792 // visiting the current node and its subtree. | 760 // visiting the current node and its subtree. |
| 793 continue; | 761 continue; |
| 794 } | 762 } |
| 795 for (Link<ClassHierarchyNode> link = currentNode._directSubclasses; | 763 for (Link<ClassHierarchyNode> link = currentNode._directSubclasses; |
| 796 !link.isEmpty; | 764 !link.isEmpty; |
| 797 link = link.tail) { | 765 link = link.tail) { |
| 798 stack = stack.prepend(link.head); | 766 stack = stack.prepend(link.head); |
| 799 } | 767 } |
| 800 if (_isValid(currentNode)) { | 768 if (_isValid(currentNode)) { |
| 801 return true; | 769 return true; |
| 802 } | 770 } |
| 803 } | 771 } |
| 804 } | 772 } |
| 805 | 773 |
| 806 /// Returns `true` if the class of [node] is a valid result for this iterator. | 774 /// Returns `true` if the class of [node] is a valid result for this iterator. |
| 807 bool _isValid(ClassHierarchyNode node) { | 775 bool _isValid(ClassHierarchyNode node) { |
| 808 if (!includeRoot && node == root) return false; | 776 if (!includeRoot && node == root) return false; |
| 809 return mask.intersects(node._mask); | 777 return mask.intersects(node._mask); |
| 810 } | 778 } |
| 811 } | 779 } |
| 812 | 780 |
| 813 /// Iterable for the subtypes in a [ClassSet]. | 781 /// Iterable for the subtypes in a [ClassSet]. |
| 814 class SubtypesIterable extends IterableBase<ClassElement> { | 782 class SubtypesIterable extends IterableBase<ClassElement> { |
| 815 final ClassSet subtypeSet; | 783 final ClassSet subtypeSet; |
| 816 final EnumSet<Instantiation> mask; | 784 final EnumSet<Instantiation> mask; |
| 817 final bool includeRoot; | 785 final bool includeRoot; |
| 818 | 786 |
| 819 SubtypesIterable.SubtypesIterator( | 787 SubtypesIterable.SubtypesIterator(this.subtypeSet, this.mask, |
| 820 this.subtypeSet, | |
| 821 this.mask, | |
| 822 {this.includeRoot: true}); | 788 {this.includeRoot: true}); |
| 823 | 789 |
| 824 @override | 790 @override |
| 825 Iterator<ClassElement> get iterator => new SubtypesIterator(this); | 791 Iterator<ClassElement> get iterator => new SubtypesIterator(this); |
| 826 } | 792 } |
| 827 | 793 |
| 828 /// Iterator for the subtypes in a [ClassSet]. | 794 /// Iterator for the subtypes in a [ClassSet]. |
| 829 class SubtypesIterator extends Iterator<ClassElement> { | 795 class SubtypesIterator extends Iterator<ClassElement> { |
| 830 final SubtypesIterable iterable; | 796 final SubtypesIterable iterable; |
| 831 Iterator<ClassElement> elements; | 797 Iterator<ClassElement> elements; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 842 if (elements != null) { | 808 if (elements != null) { |
| 843 return elements.current; | 809 return elements.current; |
| 844 } | 810 } |
| 845 return null; | 811 return null; |
| 846 } | 812 } |
| 847 | 813 |
| 848 @override | 814 @override |
| 849 bool moveNext() { | 815 bool moveNext() { |
| 850 if (elements == null && hierarchyNodes == null) { | 816 if (elements == null && hierarchyNodes == null) { |
| 851 // Initial state. Iterate through subclasses. | 817 // Initial state. Iterate through subclasses. |
| 852 elements = iterable.subtypeSet.node.subclassesByMask( | 818 elements = iterable.subtypeSet.node |
| 853 mask, | 819 .subclassesByMask(mask, strict: !includeRoot) |
| 854 strict: !includeRoot).iterator; | 820 .iterator; |
| 855 } | 821 } |
| 856 if (elements != null && elements.moveNext()) { | 822 if (elements != null && elements.moveNext()) { |
| 857 return true; | 823 return true; |
| 858 } | 824 } |
| 859 if (hierarchyNodes == null) { | 825 if (hierarchyNodes == null) { |
| 860 // Start iterating through subtypes. | 826 // Start iterating through subtypes. |
| 861 hierarchyNodes = iterable.subtypeSet._subtypes.iterator; | 827 hierarchyNodes = iterable.subtypeSet._subtypes.iterator; |
| 862 } | 828 } |
| 863 while (hierarchyNodes.moveNext()) { | 829 while (hierarchyNodes.moveNext()) { |
| 864 elements = hierarchyNodes.current.subclassesByMask(mask).iterator; | 830 elements = hierarchyNodes.current.subclassesByMask(mask).iterator; |
| 865 if (elements.moveNext()) { | 831 if (elements.moveNext()) { |
| 866 return true; | 832 return true; |
| 867 } | 833 } |
| 868 } | 834 } |
| 869 return false; | 835 return false; |
| 870 } | 836 } |
| 871 } | 837 } |
| 872 | 838 |
| 873 /// Enum values returned from the [ForEachFunction] provided to the `forEachX` | 839 /// Enum values returned from the [ForEachFunction] provided to the `forEachX` |
| 874 /// functions of [ClassHierarchyNode] and [ClassSet]. The value is used to | 840 /// functions of [ClassHierarchyNode] and [ClassSet]. The value is used to |
| 875 /// control the continued iteration. | 841 /// control the continued iteration. |
| 876 enum IterationStep { | 842 enum IterationStep { |
| 877 /// Iteration continues. | 843 /// Iteration continues. |
| 878 CONTINUE, | 844 CONTINUE, |
| 845 |
| 879 /// Iteration stops immediately. | 846 /// Iteration stops immediately. |
| 880 STOP, | 847 STOP, |
| 848 |
| 881 /// Iteration skips the subclasses of the current class. | 849 /// Iteration skips the subclasses of the current class. |
| 882 SKIP_SUBCLASSES, | 850 SKIP_SUBCLASSES, |
| 883 } | 851 } |
| 884 | 852 |
| 885 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] | 853 /// Visiting function used for the `forEachX` functions of [ClassHierarchyNode] |
| 886 /// and [ClassSet]. The return value controls the continued iteration. If `null` | 854 /// and [ClassSet]. The return value controls the continued iteration. If `null` |
| 887 /// is returned, iteration continues to the end. | 855 /// is returned, iteration continues to the end. |
| 888 typedef IterationStep ForEachFunction(ClassElement cls); | 856 typedef IterationStep ForEachFunction(ClassElement cls); |
| OLD | NEW |