| // 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 { |
| 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>{}; |
| |
| 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<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]; |
| } |
| } |
| } |
| |
| 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<Member> getDispatchTargets(Class class_, {bool setters: false}) { |
| return setters |
| ? this.setters[class_].values |
| : gettersAndCalls[class_].values; |
| } |
| |
| Member tryFirst(List<Member> 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<Member> getInterfaceMembersByName(Class class_, Name name, |
| {bool setter: false}) { |
| var iterable = setter |
| ? interfaceSetters[class_][name] |
| : interfaceGettersAndCalls[class_][name]; |
| return iterable == null ? const <Member>[] : iterable; |
| } |
| |
| List<Member> 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<int> getExpenseHistogram() => <int>[]; |
| double getCompressionRatio() => 0.0; |
| int getSuperTypeHashTableSize() => 0; |
| |
| noSuchMethod(inv) => super.noSuchMethod(inv); |
| } |