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 |