Index: pkg/compiler/lib/src/universe/class_set.dart |
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart |
index b4189767efb3e31b5fd7cf57b29a377af629b042..ac856a2802b6f84db10c158034822b74b4c3a9a6 100644 |
--- a/pkg/compiler/lib/src/universe/class_set.dart |
+++ b/pkg/compiler/lib/src/universe/class_set.dart |
@@ -35,6 +35,7 @@ import '../util/util.dart' show Link; |
/// |
class ClassHierarchyNode { |
final ClassElement cls; |
+ ClassElement _leastUpperInstantiatedSubclass; |
/// `true` if [cls] has been directly instantiated. |
/// |
@@ -101,15 +102,55 @@ class ClassHierarchyNode { |
includeUninstantiated: includeUninstantiated); |
} |
+ /// Returns the most specific subclass of [cls] (including [cls]) that is |
+ /// directly instantiated or a superclass of all directly instantiated |
+ /// subclasses. If [cls] is not instantiated, `null` is returned. |
+ ClassElement getLubOfInstantiatedSubclasses() { |
+ if (!isInstantiated) return null; |
+ if (_leastUpperInstantiatedSubclass == null) { |
+ _leastUpperInstantiatedSubclass = |
+ _computeLeastUpperInstantiatedSubclass(); |
+ } |
+ return _leastUpperInstantiatedSubclass; |
+ } |
+ |
+ ClassElement _computeLeastUpperInstantiatedSubclass() { |
+ if (isDirectlyInstantiated) { |
+ return cls; |
+ } |
+ ClassHierarchyNode subclass; |
+ for (Link<ClassHierarchyNode> link = _directSubclasses; |
+ !link.isEmpty; |
+ link = link.tail) { |
+ if (link.head.isInstantiated) { |
+ if (subclass == null) { |
+ subclass = link.head; |
+ } else { |
+ return cls; |
+ } |
+ } |
+ } |
+ if (subclass != null) { |
+ return subclass.getLubOfInstantiatedSubclasses(); |
+ } |
+ return cls; |
+ } |
+ |
void printOn(StringBuffer sb, String indentation, |
{bool instantiatedOnly: false, |
+ bool sorted: true, |
ClassElement withRespectTo}) { |
bool isRelatedTo(ClassElement subclass) { |
- return subclass.implementsInterface(withRespectTo); |
+ return subclass == withRespectTo || |
+ subclass.implementsInterface(withRespectTo); |
} |
- sb.write('$indentation$cls'); |
+ sb.write(indentation); |
+ if (cls.isAbstract) { |
+ sb.write('abstract '); |
+ } |
+ sb.write('class ${cls.name}:'); |
if (isDirectlyInstantiated) { |
sb.write(' directly'); |
} |
@@ -120,11 +161,14 @@ class ClassHierarchyNode { |
if (_directSubclasses.isEmpty) { |
sb.write(']'); |
} else { |
+ var subclasses = _directSubclasses; |
+ if (sorted) { |
+ subclasses = _directSubclasses.toList()..sort((a, b) { |
+ return a.cls.name.compareTo(b.cls.name); |
+ }); |
+ } |
bool needsComma = false; |
- for (Link<ClassHierarchyNode> link = _directSubclasses; |
- !link.isEmpty; |
- link = link.tail) { |
- ClassHierarchyNode child = link.head; |
+ for (ClassHierarchyNode child in subclasses) { |
if (instantiatedOnly && !child.isInstantiated) { |
continue; |
} |
@@ -140,6 +184,7 @@ class ClassHierarchyNode { |
sb, |
'$indentation ', |
instantiatedOnly: instantiatedOnly, |
+ sorted: sorted, |
withRespectTo: withRespectTo); |
needsComma = true; |
} |
@@ -211,6 +256,7 @@ class ClassHierarchyNode { |
/// |
class ClassSet { |
final ClassHierarchyNode node; |
+ ClassElement _leastUpperInstantiatedSubtype; |
List<ClassHierarchyNode> _directSubtypes; |
@@ -311,6 +357,42 @@ class ClassSet { |
} |
} |
+ /// Returns the most specific subtype of [cls] (including [cls]) that is |
+ /// directly instantiated or a superclass of all directly instantiated |
+ /// subtypes. If no subtypes of [cls] are instantiated, `null` is returned. |
+ ClassElement getLubOfInstantiatedSubtypes() { |
+ if (_leastUpperInstantiatedSubtype == null) { |
+ _leastUpperInstantiatedSubtype = _computeLeastUpperInstantiatedSubtype(); |
+ } |
+ return _leastUpperInstantiatedSubtype; |
+ } |
+ |
+ ClassElement _computeLeastUpperInstantiatedSubtype() { |
+ if (node.isDirectlyInstantiated) { |
+ return cls; |
+ } |
+ if (_directSubtypes == null) { |
+ return node.getLubOfInstantiatedSubclasses(); |
+ } |
+ ClassHierarchyNode subtype; |
+ if (node.isInstantiated) { |
+ subtype = node; |
+ } |
+ for (ClassHierarchyNode subnode in _directSubtypes) { |
+ if (subnode.isInstantiated) { |
+ if (subtype == null) { |
+ subtype = subnode; |
+ } else { |
+ return cls; |
+ } |
+ } |
+ } |
+ if (subtype != null) { |
+ return subtype.getLubOfInstantiatedSubclasses(); |
+ } |
+ return null; |
+ } |
+ |
String toString() { |
StringBuffer sb = new StringBuffer(); |
sb.write('[\n'); |