// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. library kernel.class_hierarchy_basic; import 'package:kernel/class_hierarchy.dart'; import 'package:kernel/type_algebra.dart'; import 'package:kernel/ast.dart'; /// A simple implementation of the class hierarchy interface using /// hash tables for everything. class BasicClassHierarchy implements ClassHierarchy { @override final Set knownLibraries; final Map> superclasses = >{}; final Map> superMixtures = >{}; final Map> supertypes = >{}; final Map> supertypeInstantiations = >{}; final Map> gettersAndCalls = >{}; final Map> setters = >{}; final Map>> interfaceGettersAndCalls = >>{}; final Map>> interfaceSetters = >>{}; final List classes = []; final Map classIndex = {}; BasicClassHierarchy(Component component) : knownLibraries = component.libraries.toSet() { for (var library in knownLibraries) { for (var classNode in library.classes) { buildSuperTypeSets(classNode); buildSuperTypeInstantiations(classNode); buildDispatchTable(classNode); buildInterfaceTable(classNode); } } } @override void forEachOverridePair( Class class_, callback(Member member, Member superMember, bool setter)) { void report(Member member, Member superMember, bool setter) { if (!identical(member, superMember)) { callback(member, superMember, setter); } } // Report declared members overriding inheritable members. for (var member in class_.mixin.members) { for (var supertype in class_.supers) { if (member.hasGetter) { for (var superMember in getInterfaceMembersByName(supertype.classNode, member.name)) { report(member, superMember, false); } } if (member.hasSetter) { for (var superMember in getInterfaceMembersByName( supertype.classNode, member.name, setter: true)) { report(member, superMember, true); } } } } // Report inherited non-abstract members overriding inheritable or // declared members. for (var setter in [true, false]) { for (var member in getDispatchTargets(class_, setters: setter)) { // Report overriding inheritable members. for (var supertype in class_.supers) { for (var superMember in getInterfaceMembersByName( supertype.classNode, member.name, setter: setter)) { report(member, superMember, setter); } } // Report overriding declared abstract members. if (!class_.isAbstract && member.enclosingClass != class_.mixin) { for (var declaredMember in getInterfaceMembersByName( class_, member.name, setter: setter)) { report(member, declaredMember, setter); } } } } } void buildSuperTypeSets(Class node) { if (superclasses.containsKey(node)) return; superclasses[node] = new Set()..add(node); superMixtures[node] = new Set()..add(node); supertypes[node] = new Set()..add(node); if (node.supertype != null) { buildSuperTypeSets(node.supertype!.classNode); superclasses[node]!.addAll(superclasses[node.supertype!.classNode]!); superMixtures[node]!.addAll(superMixtures[node.supertype!.classNode]!); supertypes[node]!.addAll(supertypes[node.supertype!.classNode]!); } if (node.mixedInType != null) { buildSuperTypeSets(node.mixedInType!.classNode); superMixtures[node]!.addAll(superMixtures[node.mixedInType!.classNode]!); supertypes[node]!.addAll(supertypes[node.mixedInType!.classNode]!); } for (var supertype in node.implementedTypes) { buildSuperTypeSets(supertype.classNode); supertypes[node]!.addAll(supertypes[supertype.classNode]!); } classes.add(node); classIndex[node] = classes.length - 1; } void buildSuperTypeInstantiations(Class node) { if (supertypeInstantiations.containsKey(node)) return; supertypeInstantiations[node] = { node: node.asThisSupertype }; for (var supertype in node.supers) { var superclass = supertype.classNode; buildSuperTypeInstantiations(superclass); var substitution = Substitution.fromPairs( superclass.typeParameters, supertype.typeArguments); supertypeInstantiations[superclass]!.forEach((key, type) { supertypeInstantiations[node]![key] = substitution.substituteSupertype(type); }); } } void buildDispatchTable(Class node) { if (gettersAndCalls.containsKey(node)) return; gettersAndCalls[node] = {}; setters[node] = {}; if (node.supertype != null) { buildDispatchTable(node.supertype!.classNode); gettersAndCalls[node]! .addAll(gettersAndCalls[node.supertype!.classNode]!); setters[node]!.addAll(setters[node.supertype!.classNode]!); } // Overwrite map entries with declared members. Class mixin = node.mixedInType?.classNode ?? node; for (Procedure procedure in mixin.procedures) { if (procedure.isStatic || procedure.isAbstract) continue; if (procedure.kind == ProcedureKind.Setter) { setters[node]![procedure.name] = procedure; } else { gettersAndCalls[node]![procedure.name] = procedure; } } for (Field field in mixin.fields) { if (field.isStatic) continue; gettersAndCalls[node]![field.name] = field; if (!field.isFinal) { setters[node]![field.name] = field; } } } void mergeMaps( Map> source, Map> destination) { for (var name in source.keys) { destination.putIfAbsent(name, () => []).addAll(source[name]!); } } void buildInterfaceTable(Class node) { if (interfaceGettersAndCalls.containsKey(node)) return; interfaceGettersAndCalls[node] = >{}; interfaceSetters[node] = >{}; void inheritFrom(Supertype? type) { if (type == null) return; buildInterfaceTable(type.classNode); mergeMaps(interfaceGettersAndCalls[type.classNode]!, interfaceGettersAndCalls[node]!); mergeMaps(interfaceSetters[type.classNode]!, interfaceSetters[node]!); } inheritFrom(node.supertype); inheritFrom(node.mixedInType); node.implementedTypes.forEach(inheritFrom); // Overwrite map entries with declared members. for (Procedure procedure in node.mixin.procedures) { if (procedure.isStatic) continue; if (procedure.kind == ProcedureKind.Setter) { interfaceSetters[node]![procedure.name] = [procedure]; } else { interfaceGettersAndCalls[node]![procedure.name] = [procedure]; } } for (Field field in node.mixin.fields) { if (field.isStatic) continue; interfaceGettersAndCalls[node]![field.name] = [field]; if (!field.isFinal) { interfaceSetters[node]![field.name] = [field]; } } } @override bool isSubclassOf(Class subtype, Class supertype) { return superclasses[subtype]!.contains(supertype); } bool isSubmixtureOf(Class subtype, Class supertype) { return superMixtures[subtype]!.contains(supertype); } @override bool isSubInterfaceOf(Class subtype, Class supertype) { return supertypes[subtype]!.contains(supertype); } @override Supertype? getClassAsInstanceOf(Class type, Class supertype) { return supertypeInstantiations[type]![supertype]; } @override Member? getDispatchTarget(Class class_, Name name, {bool setter = false}) { return setter ? setters[class_]![name] : gettersAndCalls[class_]![name]; } @override List getDispatchTargets(Class class_, {bool setters = false}) { return setters ? this.setters[class_]!.values.toList() : gettersAndCalls[class_]!.values.toList(); } Member? tryFirst(Iterable? members) { return (members == null || members.isEmpty) ? null : members.first; } @override Member? getInterfaceMember(Class class_, Name name, {bool setter = false}) { return tryFirst(getInterfaceMembersByName(class_, name, setter: setter)); } Iterable getInterfaceMembersByName(Class class_, Name name, {bool setter = false}) { var iterable = setter ? interfaceSetters[class_]![name] : interfaceGettersAndCalls[class_]![name]; return iterable == null ? const [] : iterable; } @override List getInterfaceMembers(Class class_, {bool setters = false}) { return setters ? interfaceSetters[class_]!.values.expand((x) => x).toList() : interfaceGettersAndCalls[class_]!.values.expand((x) => x).toList(); } int getClassIndex(Class node) { return classIndex[node]!; } List getExpenseHistogram() => []; double getCompressionRatio() => 0.0; int getSuperTypeHashTableSize() => 0; @override dynamic noSuchMethod(inv) => super.noSuchMethod(inv); }