blob: a4f3d5a38f87a5a4ba44b268e3f55703b5e564a3 [file] [log] [blame]
package com.android.tools.r8.graph;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.TraversalContinuation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class MethodCollection {
private final DexClass holder;
private final MethodArrayBacking backing = new MethodArrayBacking();
private Optional<DexEncodedMethod> cachedClassInitializer = null;
public MethodCollection(DexClass holder) {
this.holder = holder;
}
public int size() {
return backing.size();
}
public TraversalContinuation traverse(Function<DexEncodedMethod, TraversalContinuation> fn) {
return backing.traverse(fn);
}
public void forEachMethod(Consumer<DexEncodedMethod> consumer) {
backing.forEachMethod(consumer);
}
public Iterable<DexEncodedMethod> methods() {
return backing.methods();
}
public Iterable<DexEncodedMethod> methods(Predicate<DexEncodedMethod> predicate) {
return IterableUtils.filter(methods(), predicate);
}
public List<DexEncodedMethod> allMethodsSorted() {
List<DexEncodedMethod> sorted = new ArrayList<>(size());
forEachMethod(sorted::add);
sorted.sort((a, b) -> a.method.slowCompareTo(b.method));
return sorted;
}
public List<DexEncodedMethod> directMethods() {
return backing.directMethods();
}
public List<DexEncodedMethod> virtualMethods() {
return backing.virtualMethods();
}
public DexEncodedMethod getMethod(DexMethod method) {
return backing.getMethod(method);
}
public DexEncodedMethod getDirectMethod(DexMethod method) {
return backing.getDirectMethod(method);
}
public DexEncodedMethod getDirectMethod(Predicate<DexEncodedMethod> predicate) {
return backing.getDirectMethod(predicate);
}
public DexEncodedMethod getVirtualMethod(DexMethod method) {
return backing.getVirtualMethod(method);
}
public DexEncodedMethod getVirtualMethod(Predicate<DexEncodedMethod> predicate) {
return backing.getVirtualMethod(predicate);
}
public DexEncodedMethod getClassInitializer() {
if (cachedClassInitializer == null) {
cachedClassInitializer = Optional.empty();
for (DexEncodedMethod directMethod : directMethods()) {
if (directMethod.isClassInitializer()) {
cachedClassInitializer = Optional.of(directMethod);
break;
}
}
}
return cachedClassInitializer.orElse(null);
}
public void addMethod(DexEncodedMethod method) {
backing.addMethod(method);
}
public void addVirtualMethod(DexEncodedMethod virtualMethod) {
backing.addVirtualMethod(virtualMethod);
}
public void addDirectMethod(DexEncodedMethod directMethod) {
cachedClassInitializer = null;
backing.addDirectMethod(directMethod);
}
public DexEncodedMethod replaceDirectMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
cachedClassInitializer = null;
return backing.replaceDirectMethod(method, replacement);
}
public void replaceMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
backing.replaceMethods(replacement);
}
public void replaceVirtualMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
backing.replaceVirtualMethods(replacement);
}
public void replaceDirectMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
cachedClassInitializer = null;
backing.replaceDirectMethods(replacement);
}
/**
* Replace a direct method, if found, by a computed virtual method using the replacement function.
*
* @param method Direct method to replace if present.
* @param replacement Replacement function computing the virtual replacement.
* @return Returns the replacement if found, null otherwise.
*/
public DexEncodedMethod replaceDirectMethodWithVirtualMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
// The class initializer can never by converted to a virtual.
return backing.replaceDirectMethodWithVirtualMethod(method, replacement);
}
public void appendDirectMethod(DexEncodedMethod method) {
assert verifyCorrectnessOfMethodHolder(method);
cachedClassInitializer = null;
backing.appendDirectMethod(method);
}
public void appendDirectMethods(Collection<DexEncodedMethod> methods) {
assert verifyCorrectnessOfMethodHolders(methods);
cachedClassInitializer = null;
backing.appendDirectMethods(methods);
}
public void removeDirectMethod(DexMethod method) {
cachedClassInitializer = null;
backing.removeDirectMethod(method);
}
public void setDirectMethods(DexEncodedMethod[] methods) {
assert verifyCorrectnessOfMethodHolders(methods);
cachedClassInitializer = null;
backing.setDirectMethods(methods);
}
public void appendVirtualMethod(DexEncodedMethod method) {
assert verifyCorrectnessOfMethodHolder(method);
backing.appendVirtualMethod(method);
}
public void appendVirtualMethods(Collection<DexEncodedMethod> methods) {
assert verifyCorrectnessOfMethodHolders(methods);
backing.appendVirtualMethods(methods);
}
public void setVirtualMethods(DexEncodedMethod[] methods) {
assert verifyCorrectnessOfMethodHolders(methods);
backing.setVirtualMethods(methods);
}
public void virtualizeMethods(Set<DexEncodedMethod> privateInstanceMethods) {
backing.virtualizeMethods(privateInstanceMethods);
}
public boolean hasAnnotations() {
return traverse(
method ->
method.hasAnnotation()
? TraversalContinuation.BREAK
: TraversalContinuation.CONTINUE)
.shouldBreak();
}
public boolean verify() {
forEachMethod(
method -> {
assert verifyCorrectnessOfMethodHolder(method);
});
assert backing.verifyNoDuplicateMethods();
return true;
}
private boolean verifyCorrectnessOfMethodHolder(DexEncodedMethod method) {
assert method.method.holder == holder.type
: "Expected method `"
+ method.method.toSourceString()
+ "` to have holder `"
+ holder.type.toSourceString()
+ "`";
return true;
}
private boolean verifyCorrectnessOfMethodHolders(DexEncodedMethod[] methods) {
if (methods == null) {
return true;
}
return verifyCorrectnessOfMethodHolders(Arrays.asList(methods));
}
private boolean verifyCorrectnessOfMethodHolders(Iterable<DexEncodedMethod> methods) {
for (DexEncodedMethod method : methods) {
assert verifyCorrectnessOfMethodHolder(method);
}
return true;
}
}