| // 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<Library> knownLibraries; | |
| final Map<Class, Set<Class>> superclasses = <Class, Set<Class>>{}; | |
| final Map<Class, Set<Class>> superMixtures = <Class, Set<Class>>{}; | |
| final Map<Class, Set<Class>> supertypes = <Class, Set<Class>>{}; | |
| final Map<Class, Map<Class, Supertype>> supertypeInstantiations = | |
| <Class, Map<Class, Supertype>>{}; | |
| final Map<Class, Map<Name, Member>> gettersAndCalls = | |
| <Class, Map<Name, Member>>{}; | |
| final Map<Class, Map<Name, Member>> setters = <Class, Map<Name, Member>>{}; | |
| final Map<Class, Map<Name, List<Member>>> interfaceGettersAndCalls = | |
| <Class, Map<Name, List<Member>>>{}; | |
| final Map<Class, Map<Name, List<Member>>> interfaceSetters = | |
| <Class, Map<Name, List<Member>>>{}; | |
| final List<Class> classes = <Class>[]; | |
| final Map<Class, int> classIndex = <Class, int>{}; | |
| new(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<Class>()..add(node); | |
| superMixtures[node] = new Set<Class>()..add(node); | |
| supertypes[node] = new Set<Class>()..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] = <Class, Supertype>{ | |
| 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] = <Name, Member>{}; | |
| setters[node] = <Name, Member>{}; | |
| 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<Name, List<Member>> source, | |
| Map<Name, List<Member>> destination, | |
| ) { | |
| for (var name in source.keys) { | |
| destination.putIfAbsent(name, () => <Member>[]).addAll(source[name]!); | |
| } | |
| } | |
| void buildInterfaceTable(Class node) { | |
| if (interfaceGettersAndCalls.containsKey(node)) return; | |
| interfaceGettersAndCalls[node] = <Name, List<Member>>{}; | |
| interfaceSetters[node] = <Name, List<Member>>{}; | |
| 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] = <Member>[procedure]; | |
| } else { | |
| interfaceGettersAndCalls[node]![procedure.name] = <Member>[procedure]; | |
| } | |
| } | |
| for (Field field in node.mixin.fields) { | |
| if (field.isStatic) continue; | |
| interfaceGettersAndCalls[node]![field.name] = <Member>[field]; | |
| if (!field.isFinal) { | |
| interfaceSetters[node]![field.name] = <Member>[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<Member> getDispatchTargets(Class class_, {bool setters = false}) { | |
| return setters | |
| ? this.setters[class_]!.values.toList() | |
| : gettersAndCalls[class_]!.values.toList(); | |
| } | |
| Member? tryFirst(Iterable<Member>? 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<Member> getInterfaceMembersByName( | |
| Class class_, | |
| Name name, { | |
| bool setter = false, | |
| }) { | |
| var iterable = setter | |
| ? interfaceSetters[class_]![name] | |
| : interfaceGettersAndCalls[class_]![name]; | |
| return iterable == null ? const <Member>[] : iterable; | |
| } | |
| @override | |
| List<Member> 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<int> getExpenseHistogram() => <int>[]; | |
| double getCompressionRatio() => 0.0; | |
| int getSuperTypeHashTableSize() => 0; | |
| @override | |
| dynamic noSuchMethod(inv) => super.noSuchMethod(inv); | |
| } |