| // Copyright (c) 2021, the R8 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. |
| |
| package com.android.tools.r8.graph; |
| |
| import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull; |
| import static com.android.tools.r8.utils.MapUtils.ignoreKey; |
| import static com.google.common.base.Predicates.alwaysTrue; |
| |
| import com.google.common.collect.Iterables; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.IdentityHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.function.BiConsumer; |
| import java.util.function.BiPredicate; |
| import java.util.function.Consumer; |
| import java.util.function.Predicate; |
| |
| public class ImmediateProgramSubtypingInfo { |
| |
| private final AppView<? extends AppInfoWithClassHierarchy> appView; |
| private final Map<DexProgramClass, List<DexProgramClass>> immediateSubtypes; |
| |
| private ImmediateProgramSubtypingInfo( |
| AppView<? extends AppInfoWithClassHierarchy> appView, |
| Map<DexProgramClass, List<DexProgramClass>> immediateSubtypes) { |
| this.appView = appView; |
| this.immediateSubtypes = immediateSubtypes; |
| } |
| |
| public static ImmediateProgramSubtypingInfo create( |
| AppView<? extends AppInfoWithClassHierarchy> appView) { |
| return internalCreate(appView, appView.appInfo().classes()); |
| } |
| |
| public static ImmediateProgramSubtypingInfo createWithDeterministicOrder( |
| AppView<? extends AppInfoWithClassHierarchy> appView) { |
| return internalCreate(appView, appView.appInfo().classesWithDeterministicOrder()); |
| } |
| |
| private static ImmediateProgramSubtypingInfo internalCreate( |
| AppView<? extends AppInfoWithClassHierarchy> appView, Collection<DexProgramClass> classes) { |
| Map<DexProgramClass, List<DexProgramClass>> immediateSubtypes = new IdentityHashMap<>(); |
| for (DexProgramClass clazz : classes) { |
| clazz.forEachImmediateSupertype( |
| supertype -> { |
| DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(supertype)); |
| if (superclass != null) { |
| immediateSubtypes.computeIfAbsent(superclass, ignoreKey(ArrayList::new)).add(clazz); |
| } |
| }); |
| } |
| return new ImmediateProgramSubtypingInfo(appView, immediateSubtypes); |
| } |
| |
| public void forEachImmediateSuperClass(DexClass clazz, Consumer<? super DexClass> consumer) { |
| forEachImmediateSuperClassMatching( |
| clazz, |
| (supertype, superclass) -> superclass != null, |
| (supertype, superclass) -> consumer.accept(superclass)); |
| } |
| |
| public void forEachImmediateSuperClass( |
| DexClass clazz, BiConsumer<? super DexType, ? super DexClass> consumer) { |
| forEachImmediateSuperClassMatching(clazz, (supertype, superclass) -> true, consumer); |
| } |
| |
| public void forEachImmediateSuperClassMatching( |
| DexClass clazz, |
| BiPredicate<? super DexType, ? super DexClass> predicate, |
| BiConsumer<? super DexType, ? super DexClass> consumer) { |
| clazz.forEachImmediateSupertype( |
| supertype -> { |
| DexClass superclass = appView.definitionFor(supertype); |
| if (predicate.test(supertype, superclass)) { |
| consumer.accept(supertype, superclass); |
| } |
| }); |
| } |
| |
| public void forEachImmediateSuperClassMatching( |
| DexClass clazz, Predicate<? super DexClass> predicate, Consumer<? super DexClass> consumer) { |
| clazz.forEachImmediateSupertype( |
| supertype -> { |
| DexClass superclass = appView.definitionFor(supertype); |
| if (superclass != null && predicate.test(superclass)) { |
| consumer.accept(superclass); |
| } |
| }); |
| } |
| |
| public void forEachImmediateProgramSuperClass( |
| DexProgramClass clazz, Consumer<? super DexProgramClass> consumer) { |
| forEachImmediateProgramSuperClassMatching(clazz, alwaysTrue(), consumer); |
| } |
| |
| public void forEachImmediateProgramSuperClassMatching( |
| DexProgramClass clazz, |
| Predicate<? super DexProgramClass> predicate, |
| Consumer<? super DexProgramClass> consumer) { |
| clazz.forEachImmediateSupertype( |
| supertype -> { |
| DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(supertype)); |
| if (superclass != null && predicate.test(superclass)) { |
| consumer.accept(superclass); |
| } |
| }); |
| } |
| |
| public void forEachImmediateSubClassMatching( |
| DexProgramClass clazz, |
| Predicate<? super DexProgramClass> predicate, |
| Consumer<? super DexProgramClass> consumer) { |
| getSubclasses(clazz) |
| .forEach( |
| subclass -> { |
| if (predicate.test(subclass)) { |
| consumer.accept(subclass); |
| } |
| }); |
| } |
| |
| public List<DexProgramClass> getSubclasses(DexProgramClass clazz) { |
| return immediateSubtypes.getOrDefault(clazz, Collections.emptyList()); |
| } |
| |
| public Iterable<DexProgramClass> getSubinterfaces(DexProgramClass clazz) { |
| assert clazz.isInterface(); |
| return Iterables.filter(getSubclasses(clazz), DexClass::isInterface); |
| } |
| |
| public Iterable<DexProgramClass> getSuperinterfaces( |
| DexProgramClass clazz, DexDefinitionSupplier definitions) { |
| return Iterables.filter( |
| Iterables.transform( |
| clazz.getInterfaces(), i -> asProgramClassOrNull(definitions.definitionFor(i, clazz))), |
| Objects::nonNull); |
| } |
| |
| public boolean hasSubclasses(DexProgramClass clazz) { |
| return !getSubclasses(clazz).isEmpty(); |
| } |
| } |