blob: c381074e72537987c722a5eb75a064d798f34346 [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.GenericSignature.getEmptyTypeArguments;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GenericSignature.ReturnType;
import com.android.tools.r8.graph.GenericSignature.TypeSignature;
import com.android.tools.r8.graph.GenericSignature.WildcardIndicator;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public class GenericSignaturePartialTypeArgumentApplier implements GenericSignatureVisitor {
private final Map<String, DexType> substitutions;
private final Set<String> liveTypeVariables;
private final DexType objectType;
private final BiPredicate<DexType, DexType> enclosingPruned;
private final Predicate<DexType> hasGenericTypeParameters;
private GenericSignaturePartialTypeArgumentApplier(
Map<String, DexType> substitutions,
Set<String> liveTypeVariables,
DexType objectType,
BiPredicate<DexType, DexType> enclosingPruned,
Predicate<DexType> hasGenericTypeParameters) {
this.substitutions = substitutions;
this.liveTypeVariables = liveTypeVariables;
this.objectType = objectType;
this.enclosingPruned = enclosingPruned;
this.hasGenericTypeParameters = hasGenericTypeParameters;
}
public static GenericSignaturePartialTypeArgumentApplier build(
DexType objectType,
BiPredicate<DexType, DexType> enclosingPruned,
Predicate<DexType> hasGenericTypeParameters) {
return new GenericSignaturePartialTypeArgumentApplier(
Collections.emptyMap(),
Collections.emptySet(),
objectType,
enclosingPruned,
hasGenericTypeParameters);
}
public GenericSignaturePartialTypeArgumentApplier addSubstitutionsAndVariables(
Map<String, DexType> substitutions, Set<String> liveTypeVariables) {
return new GenericSignaturePartialTypeArgumentApplier(
substitutions, liveTypeVariables, objectType, enclosingPruned, hasGenericTypeParameters);
}
public GenericSignaturePartialTypeArgumentApplier buildForMethod(
List<FormalTypeParameter> formals) {
if (formals.isEmpty()) {
return this;
}
ImmutableSet.Builder<String> liveVariablesBuilder = ImmutableSet.builder();
liveVariablesBuilder.addAll(liveTypeVariables);
formals.forEach(
formal -> {
liveVariablesBuilder.add(formal.name);
});
return new GenericSignaturePartialTypeArgumentApplier(
substitutions, liveTypeVariables, objectType, enclosingPruned, hasGenericTypeParameters);
}
@Override
public ClassSignature visitClassSignature(ClassSignature classSignature) {
return classSignature.visit(this);
}
@Override
public MethodTypeSignature visitMethodSignature(MethodTypeSignature methodSignature) {
return methodSignature.visit(this);
}
@Override
public DexType visitType(DexType type) {
return type;
}
@Override
public TypeSignature visitTypeSignature(TypeSignature typeSignature) {
if (typeSignature.isBaseTypeSignature()) {
return typeSignature;
}
return visitFieldTypeSignature(typeSignature.asFieldTypeSignature());
}
@Override
public FormalTypeParameter visitFormalTypeParameter(FormalTypeParameter formalTypeParameter) {
FormalTypeParameter rewritten = formalTypeParameter.visit(this);
// Guard against no information being present in bounds.
assert (rewritten.getClassBound() != null && rewritten.getClassBound().hasSignature())
|| !rewritten.getInterfaceBounds().isEmpty();
return rewritten;
}
@Override
public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) {
if (fieldSignatures == null || fieldSignatures.isEmpty()) {
return fieldSignatures;
}
return ListUtils.mapOrElse(fieldSignatures, this::visitFieldTypeSignature);
}
@Override
public List<ClassTypeSignature> visitSuperInterfaces(
List<ClassTypeSignature> interfaceSignatures) {
if (interfaceSignatures.isEmpty()) {
return interfaceSignatures;
}
return ListUtils.mapOrElse(interfaceSignatures, this::visitSuperInterface);
}
@Override
public List<FieldTypeSignature> visitTypeArguments(
DexType type, List<FieldTypeSignature> typeArguments) {
if (typeArguments.isEmpty() || !hasGenericTypeParameters.test(type)) {
return getEmptyTypeArguments();
}
return ListUtils.mapOrElse(typeArguments, this::visitFieldTypeSignature);
}
@Override
public ClassTypeSignature visitSuperInterface(ClassTypeSignature classTypeSignature) {
return classTypeSignature.visit(this);
}
@Override
public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) {
return visitFieldTypeSignature(fieldSignature);
}
@Override
public FieldTypeSignature visitInterfaceBound(FieldTypeSignature fieldSignature) {
return visitFieldTypeSignature(fieldSignature);
}
@Override
public ClassTypeSignature visitEnclosing(
ClassTypeSignature enclosingSignature, ClassTypeSignature enclosedSignature) {
if (enclosingPruned.test(enclosingSignature.type(), enclosedSignature.type())) {
return null;
} else {
return enclosingSignature.visit(this);
}
}
@Override
public List<TypeSignature> visitThrowsSignatures(List<TypeSignature> typeSignatures) {
if (typeSignatures.isEmpty()) {
return typeSignatures;
}
return ListUtils.mapOrElse(typeSignatures, this::visitTypeSignature);
}
@Override
public ReturnType visitReturnType(ReturnType returnType) {
if (returnType.isVoidDescriptor()) {
return returnType;
}
TypeSignature originalSignature = returnType.typeSignature;
TypeSignature rewrittenSignature = visitTypeSignature(originalSignature);
if (originalSignature == rewrittenSignature) {
return returnType;
}
return new ReturnType(rewrittenSignature);
}
@Override
public List<FormalTypeParameter> visitFormalTypeParameters(
List<FormalTypeParameter> formalTypeParameters) {
if (formalTypeParameters.isEmpty()) {
return formalTypeParameters;
}
return ListUtils.mapOrElse(formalTypeParameters, this::visitFormalTypeParameter);
}
@Override
public List<TypeSignature> visitMethodTypeSignatures(List<TypeSignature> typeSignatures) {
if (typeSignatures.isEmpty()) {
return typeSignatures;
}
return ListUtils.mapOrElse(typeSignatures, this::visitTypeSignature);
}
@Override
public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
return classTypeSignature.visit(this);
}
@Override
public FieldTypeSignature visitFieldTypeSignature(FieldTypeSignature fieldSignature) {
if (fieldSignature.isStar()) {
return fieldSignature;
} else if (fieldSignature.isClassTypeSignature()) {
return fieldSignature.asClassTypeSignature().visit(this);
} else if (fieldSignature.isArrayTypeSignature()) {
return fieldSignature.asArrayTypeSignature().visit(this);
} else {
assert fieldSignature.isTypeVariableSignature();
String typeVariableName = fieldSignature.asTypeVariableSignature().typeVariable();
if (substitutions.containsKey(typeVariableName)
&& !liveTypeVariables.contains(typeVariableName)) {
DexType substitution = substitutions.get(typeVariableName);
if (substitution == null) {
substitution = objectType;
}
return new ClassTypeSignature(substitution).asArgument(WildcardIndicator.NONE);
}
return fieldSignature;
}
}
}