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 import '../elements/elements.dart' show ClassElement; | 8 import '../elements/elements.dart' show ClassElement; |
9 import '../util/util.dart' show Link; | 9 import '../util/util.dart' show Link; |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 /// A | 28 /// A |
29 /// / \ | 29 /// / \ |
30 /// B C | 30 /// B C |
31 /// | | 31 /// | |
32 /// D | 32 /// D |
33 /// | | 33 /// | |
34 /// E | 34 /// E |
35 /// | 35 /// |
36 class ClassHierarchyNode { | 36 class ClassHierarchyNode { |
37 final ClassElement cls; | 37 final ClassElement cls; |
38 ClassElement _leastUpperInstantiatedSubclass; | |
39 | 38 |
40 /// `true` if [cls] has been directly instantiated. | 39 /// `true` if [cls] has been directly instantiated. |
41 /// | 40 /// |
42 /// For instance `C` but _not_ `B` in: | 41 /// For instance `C` but _not_ `B` in: |
43 /// class B {} | 42 /// class B {} |
44 /// class C extends B {} | 43 /// class C extends B {} |
45 /// main() => new C(); | 44 /// main() => new C(); |
46 /// | 45 /// |
47 bool isDirectlyInstantiated = false; | 46 bool isDirectlyInstantiated = false; |
48 | 47 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 bool includeUninstantiated: true, | 94 bool includeUninstantiated: true, |
96 bool strict: false}) { | 95 bool strict: false}) { |
97 return new ClassHierarchyNodeIterable( | 96 return new ClassHierarchyNodeIterable( |
98 this, | 97 this, |
99 includeRoot: !strict, | 98 includeRoot: !strict, |
100 includeDirectlyInstantiated: includeDirectlyInstantiated, | 99 includeDirectlyInstantiated: includeDirectlyInstantiated, |
101 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | 100 includeIndirectlyInstantiated: includeIndirectlyInstantiated, |
102 includeUninstantiated: includeUninstantiated); | 101 includeUninstantiated: includeUninstantiated); |
103 } | 102 } |
104 | 103 |
105 /// Returns the most specific subclass of [cls] (including [cls]) that is | |
106 /// directly instantiated or a superclass of all directly instantiated | |
107 /// subclasses. If [cls] is not instantiated, `null` is returned. | |
108 ClassElement getLubOfInstantiatedSubclasses() { | |
109 if (!isInstantiated) return null; | |
110 if (_leastUpperInstantiatedSubclass == null) { | |
111 _leastUpperInstantiatedSubclass = | |
112 _computeLeastUpperInstantiatedSubclass(); | |
113 } | |
114 return _leastUpperInstantiatedSubclass; | |
115 } | |
116 | |
117 ClassElement _computeLeastUpperInstantiatedSubclass() { | |
118 if (isDirectlyInstantiated) { | |
119 return cls; | |
120 } | |
121 ClassHierarchyNode subclass; | |
122 for (Link<ClassHierarchyNode> link = _directSubclasses; | |
123 !link.isEmpty; | |
124 link = link.tail) { | |
125 if (link.head.isInstantiated) { | |
126 if (subclass == null) { | |
127 subclass = link.head; | |
128 } else { | |
129 return cls; | |
130 } | |
131 } | |
132 } | |
133 if (subclass != null) { | |
134 return subclass.getLubOfInstantiatedSubclasses(); | |
135 } | |
136 return cls; | |
137 } | |
138 | |
139 void printOn(StringBuffer sb, String indentation, | 104 void printOn(StringBuffer sb, String indentation, |
140 {bool instantiatedOnly: false, | 105 {bool instantiatedOnly: false, |
141 bool sorted: true, | |
142 ClassElement withRespectTo}) { | 106 ClassElement withRespectTo}) { |
143 | 107 |
144 bool isRelatedTo(ClassElement subclass) { | 108 bool isRelatedTo(ClassElement subclass) { |
145 return subclass == withRespectTo || | 109 return subclass.implementsInterface(withRespectTo); |
146 subclass.implementsInterface(withRespectTo); | |
147 } | 110 } |
148 | 111 |
149 sb.write(indentation); | 112 sb.write('$indentation$cls'); |
150 if (cls.isAbstract) { | |
151 sb.write('abstract '); | |
152 } | |
153 sb.write('class ${cls.name}:'); | |
154 if (isDirectlyInstantiated) { | 113 if (isDirectlyInstantiated) { |
155 sb.write(' directly'); | 114 sb.write(' directly'); |
156 } | 115 } |
157 if (isIndirectlyInstantiated) { | 116 if (isIndirectlyInstantiated) { |
158 sb.write(' indirectly'); | 117 sb.write(' indirectly'); |
159 } | 118 } |
160 sb.write(' ['); | 119 sb.write(' ['); |
161 if (_directSubclasses.isEmpty) { | 120 if (_directSubclasses.isEmpty) { |
162 sb.write(']'); | 121 sb.write(']'); |
163 } else { | 122 } else { |
164 var subclasses = _directSubclasses; | |
165 if (sorted) { | |
166 subclasses = _directSubclasses.toList()..sort((a, b) { | |
167 return a.cls.name.compareTo(b.cls.name); | |
168 }); | |
169 } | |
170 bool needsComma = false; | 123 bool needsComma = false; |
171 for (ClassHierarchyNode child in subclasses) { | 124 for (Link<ClassHierarchyNode> link = _directSubclasses; |
| 125 !link.isEmpty; |
| 126 link = link.tail) { |
| 127 ClassHierarchyNode child = link.head; |
172 if (instantiatedOnly && !child.isInstantiated) { | 128 if (instantiatedOnly && !child.isInstantiated) { |
173 continue; | 129 continue; |
174 } | 130 } |
175 if (withRespectTo != null && !child.subclasses().any(isRelatedTo)) { | 131 if (withRespectTo != null && !child.subclasses().any(isRelatedTo)) { |
176 continue; | 132 continue; |
177 } | 133 } |
178 if (needsComma) { | 134 if (needsComma) { |
179 sb.write(',\n'); | 135 sb.write(',\n'); |
180 } else { | 136 } else { |
181 sb.write('\n'); | 137 sb.write('\n'); |
182 } | 138 } |
183 child.printOn( | 139 child.printOn( |
184 sb, | 140 sb, |
185 '$indentation ', | 141 '$indentation ', |
186 instantiatedOnly: instantiatedOnly, | 142 instantiatedOnly: instantiatedOnly, |
187 sorted: sorted, | |
188 withRespectTo: withRespectTo); | 143 withRespectTo: withRespectTo); |
189 needsComma = true; | 144 needsComma = true; |
190 } | 145 } |
191 if (needsComma) { | 146 if (needsComma) { |
192 sb.write('\n'); | 147 sb.write('\n'); |
193 sb.write('$indentation]'); | 148 sb.write('$indentation]'); |
194 } else { | 149 } else { |
195 sb.write(']'); | 150 sb.write(']'); |
196 } | 151 } |
197 } | 152 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 /// The subtypes `B` and `E` are not directly modeled because they are implied | 204 /// The subtypes `B` and `E` are not directly modeled because they are implied |
250 /// by their subclass relation to `A` and `D`, repectively. This can be seen | 205 /// by their subclass relation to `A` and `D`, repectively. This can be seen |
251 /// if we expand the subclass subtrees: | 206 /// if we expand the subclass subtrees: |
252 /// | 207 /// |
253 /// A -> [C, D, F] | 208 /// A -> [C, D, F] |
254 /// | | | 209 /// | | |
255 /// B E | 210 /// B E |
256 /// | 211 /// |
257 class ClassSet { | 212 class ClassSet { |
258 final ClassHierarchyNode node; | 213 final ClassHierarchyNode node; |
259 ClassElement _leastUpperInstantiatedSubtype; | |
260 | 214 |
261 List<ClassHierarchyNode> _directSubtypes; | 215 List<ClassHierarchyNode> _directSubtypes; |
262 | 216 |
263 ClassSet(this.node); | 217 ClassSet(this.node); |
264 | 218 |
265 ClassElement get cls => node.cls; | 219 ClassElement get cls => node.cls; |
266 | 220 |
267 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. | 221 /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls]. |
268 /// | 222 /// |
269 /// The directly instantiated, indirectly instantiated and uninstantiated | 223 /// The directly instantiated, indirectly instantiated and uninstantiated |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 } | 304 } |
351 } | 305 } |
352 } | 306 } |
353 if (!added) { | 307 if (!added) { |
354 newSubtypes.add(subtype); | 308 newSubtypes.add(subtype); |
355 } | 309 } |
356 _directSubtypes = newSubtypes; | 310 _directSubtypes = newSubtypes; |
357 } | 311 } |
358 } | 312 } |
359 | 313 |
360 /// Returns the most specific subtype of [cls] (including [cls]) that is | |
361 /// directly instantiated or a superclass of all directly instantiated | |
362 /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. | |
363 ClassElement getLubOfInstantiatedSubtypes() { | |
364 if (_leastUpperInstantiatedSubtype == null) { | |
365 _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); | |
366 } | |
367 return _leastUpperInstantiatedSubtype; | |
368 } | |
369 | |
370 ClassElement _computeLeastUpperInstantiatedSubtype() { | |
371 if (node.isDirectlyInstantiated) { | |
372 return cls; | |
373 } | |
374 if (_directSubtypes == null) { | |
375 return node.getLubOfInstantiatedSubclasses(); | |
376 } | |
377 ClassHierarchyNode subtype; | |
378 if (node.isInstantiated) { | |
379 subtype = node; | |
380 } | |
381 for (ClassHierarchyNode subnode in _directSubtypes) { | |
382 if (subnode.isInstantiated) { | |
383 if (subtype == null) { | |
384 subtype = subnode; | |
385 } else { | |
386 return cls; | |
387 } | |
388 } | |
389 } | |
390 if (subtype != null) { | |
391 return subtype.getLubOfInstantiatedSubclasses(); | |
392 } | |
393 return null; | |
394 } | |
395 | |
396 String toString() { | 314 String toString() { |
397 StringBuffer sb = new StringBuffer(); | 315 StringBuffer sb = new StringBuffer(); |
398 sb.write('[\n'); | 316 sb.write('[\n'); |
399 node.printOn(sb, ' '); | 317 node.printOn(sb, ' '); |
400 sb.write('\n'); | 318 sb.write('\n'); |
401 if (_directSubtypes != null) { | 319 if (_directSubtypes != null) { |
402 for (ClassHierarchyNode node in _directSubtypes) { | 320 for (ClassHierarchyNode node in _directSubtypes) { |
403 node.printOn(sb, ' '); | 321 node.printOn(sb, ' '); |
404 sb.write('\n'); | 322 sb.write('\n'); |
405 } | 323 } |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 includeDirectlyInstantiated: includeDirectlyInstantiated, | 509 includeDirectlyInstantiated: includeDirectlyInstantiated, |
592 includeIndirectlyInstantiated: includeIndirectlyInstantiated, | 510 includeIndirectlyInstantiated: includeIndirectlyInstantiated, |
593 includeUninstantiated: includeUninstantiated).iterator; | 511 includeUninstantiated: includeUninstantiated).iterator; |
594 if (elements.moveNext()) { | 512 if (elements.moveNext()) { |
595 return true; | 513 return true; |
596 } | 514 } |
597 } | 515 } |
598 return false; | 516 return false; |
599 } | 517 } |
600 } | 518 } |
OLD | NEW |