// 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. // @dart = 2.9 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 { 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); } } } 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]; } } } bool isSubclassOf(Class subtype, Class supertype) { return superclasses[subtype].contains(supertype); } bool isSubmixtureOf(Class subtype, Class supertype) { return superMixtures[subtype].contains(supertype); } bool isSubtypeOf(Class subtype, Class supertype) { return supertypes[subtype].contains(supertype); } Supertype getClassAsInstanceOf(Class type, Class supertype) { return supertypeInstantiations[type][supertype]; } Member getDispatchTarget(Class class_, Name name, {bool setter: false}) { return setter ? setters[class_][name] : gettersAndCalls[class_][name]; } List getDispatchTargets(Class class_, {bool setters: false}) { return setters ? this.setters[class_].values : gettersAndCalls[class_].values; } Member tryFirst(List members) { return (members == null || members.isEmpty) ? null : members[0]; } 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; } List getInterfaceMembers(Class class_, {bool setters: false}) { return setters ? interfaceSetters[class_].values.expand((x) => x) : interfaceGettersAndCalls[class_].values.expand((x) => x); } int getClassIndex(Class node) { return classIndex[node]; } List getExpenseHistogram() => []; double getCompressionRatio() => 0.0; int getSuperTypeHashTableSize() => 0; noSuchMethod(inv) => super.noSuchMethod(inv); }