blob: a23a5a62d8d03f03f29ca37f5ef9f45994322931 [file] [log] [blame]
// Copyright (c) 2020, 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 com.android.tools.r8.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public abstract class LookupResult {
public boolean isLookupResultFailure() {
return false;
}
public boolean isLookupResultSuccess() {
return false;
}
public LookupResultFailure asLookupResultFailure() {
return null;
}
public LookupResultSuccess asLookupResultSuccess() {
return null;
}
public final void forEach(Consumer<? super LookupTarget> onTarget) {
forEach(onTarget, onTarget);
}
public abstract void forEach(
Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget);
public abstract void forEachFailureDependency(
Consumer<? super DexEncodedMethod> methodCausingFailureConsumer);
public static LookupResultSuccess createResult(
Map<DexMethod, LookupMethodTarget> methodTargets,
List<LookupLambdaTarget> lambdaTargets,
List<DexEncodedMethod> methodsCausingFailure,
LookupResultCollectionState state) {
return new LookupResultSuccess(methodTargets, lambdaTargets, methodsCausingFailure, state);
}
public static LookupResultFailure createFailedResult() {
return LookupResultFailure.INSTANCE;
}
public static LookupResultSuccess getIncompleteEmptyResult() {
return LookupResultSuccess.EMPTY_INSTANCE;
}
public static class LookupResultSuccess extends LookupResult {
private static final LookupResultSuccess EMPTY_INSTANCE =
new LookupResultSuccess(
new IdentityHashMap<>(),
Collections.emptyList(),
Collections.emptyList(),
LookupResultCollectionState.Incomplete);
private final Map<DexMethod, LookupMethodTarget> methodTargets;
private final List<LookupLambdaTarget> lambdaTargets;
private final List<DexEncodedMethod> methodsCausingFailure;
private LookupResultCollectionState state;
private LookupResultSuccess(
Map<DexMethod, LookupMethodTarget> methodTargets,
List<LookupLambdaTarget> lambdaTargets,
List<DexEncodedMethod> methodsCausingFailure,
LookupResultCollectionState state) {
this.methodTargets = methodTargets;
this.lambdaTargets = lambdaTargets;
this.methodsCausingFailure = methodsCausingFailure;
this.state = state;
}
public static Builder builder() {
return new Builder();
}
public boolean isEmpty() {
return methodTargets.isEmpty() && lambdaTargets.isEmpty();
}
public boolean hasMethodTargets() {
return !methodTargets.isEmpty();
}
public boolean hasLambdaTargets() {
return !lambdaTargets.isEmpty();
}
@Override
public void forEach(
Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget) {
methodTargets.forEach((key, value) -> onMethodTarget.accept(value));
lambdaTargets.forEach(onLambdaTarget);
}
@Override
public void forEachFailureDependency(
Consumer<? super DexEncodedMethod> methodCausingFailureConsumer) {
methodsCausingFailure.forEach(methodCausingFailureConsumer);
}
public boolean contains(DexEncodedMethod method) {
// Containment of a method in the lookup results only pertains to the method targets.
return methodTargets.containsKey(method.getReference());
}
@Override
public LookupResultSuccess asLookupResultSuccess() {
return this;
}
@Override
public boolean isLookupResultSuccess() {
return true;
}
public boolean isIncomplete() {
return state == LookupResultCollectionState.Incomplete;
}
public boolean isComplete() {
return state == LookupResultCollectionState.Complete;
}
public void setIncomplete() {
// TODO(b/148769279): Remove when we have instantiated info.
state = LookupResultCollectionState.Incomplete;
}
public LookupTarget getSingleLookupTarget() {
if (isIncomplete() || methodTargets.size() + lambdaTargets.size() > 1) {
return null;
}
// TODO(b/150932978): Check lambda targets implementation methods.
if (methodTargets.size() == 1) {
return methodTargets.values().iterator().next();
} else if (lambdaTargets.size() == 1) {
return lambdaTargets.get(0);
}
return null;
}
public enum LookupResultCollectionState {
Complete,
Incomplete,
}
public static class Builder {
private final Map<DexMethod, LookupMethodTarget> methodTargets = new IdentityHashMap<>();
private final List<LookupLambdaTarget> lambdaTargets = new ArrayList<>();
private final List<DexEncodedMethod> methodsCausingFailure = new ArrayList<>();
private final Set<DexType> typesCausingFailure = Sets.newIdentityHashSet();
private LookupResultCollectionState state;
public Builder addMethodTarget(LookupMethodTarget methodTarget) {
assert methodTarget.isMethodTarget();
methodTargets.putIfAbsent(methodTarget.asMethodTarget().getReference(), methodTarget);
return this;
}
public Builder addLambdaTarget(LookupLambdaTarget lambdaTarget) {
lambdaTargets.add(lambdaTarget);
return this;
}
public Builder addMethodCausingFailure(DexEncodedMethod methodCausingFailure) {
methodsCausingFailure.add(methodCausingFailure);
return this;
}
public Builder addTypeCausingFailure(DexType typeCausingFailure) {
typesCausingFailure.add(typeCausingFailure);
return this;
}
public Builder setState(LookupResultCollectionState state) {
this.state = state;
return this;
}
public LookupResultSuccess build() {
return new LookupResultSuccess(methodTargets, lambdaTargets, methodsCausingFailure, state);
}
}
}
public static class LookupResultFailure extends LookupResult {
private static final LookupResultFailure INSTANCE = new LookupResultFailure();
private LookupResultFailure() {
// Empty to only allow creation locally.
}
@Override
public LookupResultFailure asLookupResultFailure() {
return this;
}
@Override
public boolean isLookupResultFailure() {
return true;
}
@Override
public void forEach(
Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget) {
// Nothing to iterate for a failed lookup.
}
@Override
public void forEachFailureDependency(
Consumer<? super DexEncodedMethod> methodCausingFailureConsumer) {
// TODO: record and emit failure dependencies.
}
}
}