| // 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.KeepForRetraceApi; |
| 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 |
| @KeepForRetraceApi |
| 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 returnTypeFromTypeName(String typename) { |
| return typename.equals("void") ? null : typeFromTypeName(typename); |
| } |
| |
| 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)); |
| } |
| |
| /** Get a method reference from class reference, method name and signature. */ |
| public static MethodReference methodFromDescriptor( |
| ClassReference classReference, 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( |
| classReference, |
| 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()); |
| } |
| } |