blob: 1b67cfc5db55fed0f47896e7c787e4ed53baefa6 [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.synthesis;
import static com.android.tools.r8.synthesis.SyntheticNaming.EXTERNAL_SYNTHETIC_CLASS_SEPARATOR;
import static org.hamcrest.CoreMatchers.containsString;
import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.synthesis.SyntheticNaming.Phase;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import org.hamcrest.Matcher;
public class SyntheticItemsTestUtils {
// Private copy of the synthetic namings. This is not the compiler instance, but checking on the
// id/descriptor content is safe.
private static final SyntheticNaming naming = new SyntheticNaming();
public static String syntheticMethodName() {
return SyntheticNaming.INTERNAL_SYNTHETIC_METHOD_NAME;
}
public static ClassReference syntheticCompanionClass(Class<?> clazz) {
return syntheticCompanionClass(Reference.classFromClass(clazz));
}
public static ClassReference syntheticCompanionClass(ClassReference clazz) {
return Reference.classFromDescriptor(
InterfaceDesugaringForTesting.getCompanionClassDescriptor(clazz.getDescriptor()));
}
private static ClassReference syntheticClass(Class<?> clazz, SyntheticKind kind, int id) {
return syntheticClass(Reference.classFromClass(clazz), kind, id);
}
private static ClassReference syntheticClass(ClassReference clazz, SyntheticKind kind, int id) {
return SyntheticNaming.makeSyntheticReferenceForTest(clazz, kind, "" + id);
}
public static MethodReference syntheticBackportMethod(Class<?> clazz, int id, Method method) {
ClassReference syntheticHolder = syntheticBackportClass(clazz, id);
MethodReference originalMethod = Reference.methodFromMethod(method);
return Reference.methodFromDescriptor(
syntheticHolder.getDescriptor(),
syntheticMethodName(),
originalMethod.getMethodDescriptor());
}
public static MethodReference syntheticBackportWithForwardingMethod(
ClassReference clazz, int id, MethodReference method) {
// For backports with forwarding the backported method is not static, so the original method
// signature has the receiver type pre-pended.
ImmutableList.Builder<TypeReference> builder = ImmutableList.builder();
builder.add(method.getHolderClass()).addAll(method.getFormalTypes());
MethodReference methodWithReceiverForForwarding =
Reference.method(
method.getHolderClass(),
method.getMethodName(),
builder.build(),
method.getReturnType());
return Reference.methodFromDescriptor(
syntheticBackportWithForwardingClass(clazz, id),
syntheticMethodName(),
methodWithReceiverForForwarding.getMethodDescriptor());
}
public static ClassReference syntheticOutlineClass(Class<?> clazz, int id) {
return syntheticClass(clazz, naming.OUTLINE, id);
}
public static ClassReference syntheticOutlineClass(ClassReference clazz, int id) {
return syntheticClass(clazz, naming.OUTLINE, id);
}
public static ClassReference syntheticLambdaClass(Class<?> clazz, int id) {
return syntheticClass(clazz, naming.LAMBDA, id);
}
public static ClassReference syntheticApiOutlineClass(Class<?> clazz, int id) {
return syntheticClass(clazz, naming.API_MODEL_OUTLINE, id);
}
public static ClassReference syntheticApiOutlineClass(ClassReference classReference, int id) {
return syntheticClass(classReference, naming.API_MODEL_OUTLINE, id);
}
public static String syntheticApiOutlineClassPrefix(Class<?> clazz) {
return clazz.getTypeName()
+ EXTERNAL_SYNTHETIC_CLASS_SEPARATOR
+ naming.API_MODEL_OUTLINE.getDescriptor();
}
public static ClassReference syntheticBackportClass(Class<?> clazz, int id) {
return syntheticClass(clazz, naming.BACKPORT, id);
}
public static ClassReference syntheticBackportClass(ClassReference classReference, int id) {
return syntheticClass(classReference, naming.BACKPORT, id);
}
public static ClassReference syntheticBackportWithForwardingClass(
ClassReference classReference, int id) {
return syntheticClass(classReference, naming.BACKPORT_WITH_FORWARDING, id);
}
public static ClassReference syntheticTwrCloseResourceClass(Class<?> clazz, int id) {
return syntheticClass(clazz, naming.TWR_CLOSE_RESOURCE, id);
}
public static ClassReference syntheticTwrCloseResourceClass(ClassReference reference, int id) {
return syntheticClass(reference, naming.TWR_CLOSE_RESOURCE, id);
}
public static MethodReference syntheticLambdaMethod(Class<?> clazz, int id, Method method) {
ClassReference syntheticHolder = syntheticLambdaClass(clazz, id);
MethodReference originalMethod = Reference.methodFromMethod(method);
return Reference.methodFromDescriptor(
syntheticHolder.getDescriptor(),
originalMethod.getMethodName(),
originalMethod.getMethodDescriptor());
}
public static boolean isEnumUnboxingSharedUtilityClass(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, null, naming.ENUM_UNBOXING_SHARED_UTILITY_CLASS);
}
public static boolean isExternalSynthetic(ClassReference reference) {
for (SyntheticKind kind : naming.kinds()) {
if (kind.isGlobal()) {
continue;
}
if (kind.isFixedSuffixSynthetic()) {
if (SyntheticNaming.isSynthetic(reference, null, kind)) {
return true;
}
} else {
if (SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, kind)) {
return true;
}
}
}
return false;
}
public static boolean isInternalLambda(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, Phase.INTERNAL, naming.LAMBDA);
}
public static boolean isExternalLambda(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, naming.LAMBDA);
}
public static boolean isExternalStaticInterfaceCall(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, naming.STATIC_INTERFACE_CALL);
}
public static boolean isExternalTwrCloseMethod(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, naming.TWR_CLOSE_RESOURCE);
}
public static boolean isMaybeExternalSuppressedExceptionMethod(ClassReference reference) {
// The suppressed exception methods are grouped with the backports.
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, naming.BACKPORT);
}
public static boolean isExternalOutlineClass(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, naming.OUTLINE);
}
public static boolean isInitializerTypeArgument(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, null, naming.INIT_TYPE_ARGUMENT);
}
public static boolean isExternalNonFixedInitializerTypeArgument(ClassReference reference) {
return SyntheticNaming.isSynthetic(
reference, Phase.EXTERNAL, naming.NON_FIXED_INIT_TYPE_ARGUMENT);
}
public static boolean isHorizontalInitializerTypeArgument(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_1)
|| SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_2)
|| SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_3);
}
public static boolean isWrapper(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, null, naming.WRAPPER)
|| SyntheticNaming.isSynthetic(reference, null, naming.VIVIFIED_WRAPPER);
}
public static Matcher<String> containsInternalSyntheticReference() {
return containsString(SyntheticNaming.getPhaseSeparator(Phase.INTERNAL));
}
public static Matcher<String> containsExternalSyntheticReference() {
return containsString(SyntheticNaming.getPhaseSeparator(Phase.EXTERNAL));
}
public static boolean isInternalThrowNSME(MethodReference method) {
return SyntheticNaming.isSynthetic(method.getHolderClass(), Phase.INTERNAL, naming.THROW_NSME);
}
}