blob: 3a30ec406c117ccde323bad2fd1a262f3da7d14e [file] [log] [blame]
// Copyright (c) 2018, 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.references;
import com.android.tools.r8.Keep;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
/**
* Reference provider/factory.
*
* <p>The reference class provides a single point for creating and managing reference objects that
* represent types, methods and fields in a JVM/DEX application. The objects may or may not be
* interned/shared.
*
* <p>No guarantees are made on identity and all references must be compared by {@code equals}.
*/
@Keep
public final class Reference {
public static PrimitiveReference BOOL = PrimitiveReference.BOOL;
public static PrimitiveReference BYTE = PrimitiveReference.BYTE;
public static PrimitiveReference CHAR = PrimitiveReference.CHAR;
public static PrimitiveReference SHORT = PrimitiveReference.SHORT;
public static PrimitiveReference INT = PrimitiveReference.INT;
public static PrimitiveReference FLOAT = PrimitiveReference.FLOAT;
public static PrimitiveReference LONG = PrimitiveReference.LONG;
public static PrimitiveReference DOUBLE = PrimitiveReference.DOUBLE;
private Reference() {
// Intentionally hidden.
}
public static TypeReference returnTypeFromDescriptor(String descriptor) {
return descriptor.equals("V") ? null : typeFromDescriptor(descriptor);
}
public static TypeReference typeFromDescriptor(String descriptor) {
switch (descriptor.charAt(0)) {
case 'L':
return classFromDescriptor(descriptor);
case '[':
return arrayFromDescriptor(descriptor);
default:
return primitiveFromDescriptor(descriptor);
}
}
public static TypeReference typeFromTypeName(String typeName) {
return typeFromDescriptor(DescriptorUtils.javaTypeToDescriptor(typeName));
}
// Internal helper to convert Class<?> for primitive/array types too.
private static TypeReference typeFromClass(Class<?> clazz) {
return typeFromDescriptor(DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()));
}
public static PrimitiveReference primitiveFromDescriptor(String descriptor) {
return PrimitiveReference.fromDescriptor(descriptor);
}
/** Get a class reference from a JVM descriptor. */
public static ClassReference classFromDescriptor(String descriptor) {
return ClassReference.fromDescriptor(descriptor);
}
/**
* Get a class reference from a JVM binary name.
*
* <p>See JVM SE 9 Specification, Section 4.2.1. Binary Class and Interface Names.
*/
public static ClassReference classFromBinaryName(String binaryName) {
return classFromDescriptor(DescriptorUtils.getDescriptorFromClassBinaryName(binaryName));
}
/**
* Get a class reference from a Java type name.
*
* <p>See Class.getTypeName() from Java 1.8.
*/
public static ClassReference classFromTypeName(String typeName) {
return classFromDescriptor(DescriptorUtils.javaTypeToDescriptor(typeName));
}
/** Get a class reference from a Java java.lang.Class object. */
public static ClassReference classFromClass(Class<?> clazz) {
return classFromTypeName(clazz.getTypeName());
}
/** Get an array reference from a JVM descriptor. */
public static ArrayReference arrayFromDescriptor(String descriptor) {
return ArrayReference.fromDescriptor(descriptor);
}
/** Get an array reference from a base type and dimensions. */
public static ArrayReference array(TypeReference baseType, int dimensions) {
return ArrayReference.fromBaseType(baseType, dimensions);
}
/** Get a method reference from its full reference specification. */
public static MethodReference method(
ClassReference holderClass,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType) {
return new MethodReference(
holderClass, methodName, ImmutableList.copyOf(formalTypes), returnType);
}
/** Get a method reference from a Java reflection method. */
public static MethodReference methodFromMethod(Method method) {
String methodName = method.getName();
Class<?> holderClass = method.getDeclaringClass();
Class<?>[] parameterTypes = method.getParameterTypes();
Class<?> returnType = method.getReturnType();
ImmutableList.Builder<TypeReference> builder = ImmutableList.builder();
for (Class<?> parameterType : parameterTypes) {
builder.add(typeFromClass(parameterType));
}
return method(
classFromClass(holderClass),
methodName,
builder.build(),
returnType == Void.TYPE ? null : typeFromClass(returnType));
}
/** Get a method reference from a Java reflection constructor. */
public static MethodReference methodFromMethod(Constructor<?> method) {
Class<?> holderClass = method.getDeclaringClass();
Class<?>[] parameterTypes = method.getParameterTypes();
ImmutableList.Builder<TypeReference> builder = ImmutableList.builder();
for (Class<?> parameterType : parameterTypes) {
builder.add(typeFromClass(parameterType));
}
return method(classFromClass(holderClass), "<init>", builder.build(), null);
}
/** Get a method reference from class name, method name and signature. */
public static MethodReference methodFromDescriptor(
String classDescriptor, String methodName, String methodDescriptor) {
ImmutableList.Builder<TypeReference> builder = ImmutableList.builder();
for (String parameterTypeDescriptor :
DescriptorUtils.getArgumentTypeDescriptors(methodDescriptor)) {
builder.add(typeFromDescriptor(parameterTypeDescriptor));
}
String returnTypeDescriptor = DescriptorUtils.getReturnTypeDescriptor(methodDescriptor);
return method(
classFromDescriptor(classDescriptor),
methodName,
builder.build(),
returnTypeDescriptor.equals("V") ? null : typeFromDescriptor(returnTypeDescriptor));
}
public static MethodReference classConstructor(ClassReference type) {
return method(type, "<clinit>", Collections.emptyList(), null);
}
/** Get a field reference from its full reference specification. */
public static FieldReference field(
ClassReference holderClass, String fieldName, TypeReference fieldType) {
return new FieldReference(holderClass, fieldName, fieldType);
}
/** Get a field reference from a Java reflection field. */
public static FieldReference fieldFromField(Field field) {
Class<?> holderClass = field.getDeclaringClass();
String fieldName = field.getName();
Class<?> fieldType = field.getType();
return field(classFromClass(holderClass), fieldName, typeFromClass(fieldType));
}
/** Create a package reference from a string */
public static PackageReference packageFromString(String packageName) {
// Note, we rely on equality check for packages and do not canonicalize them.
return new PackageReference(packageName);
}
/** Create a package from a java.lang.Package */
public static PackageReference packageFromPackage(Package pkg) {
return new PackageReference(pkg.getName());
}
}