blob: dd9d171af5abd2886c2f2e33ef517b02dc96225c [file] [log] [blame]
// 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();
}
}