| // Copyright (c) 2016, 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.naming; | |
| import static com.android.tools.r8.utils.DescriptorUtils.JAVA_PACKAGE_SEPARATOR; | |
| import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor; | |
| import com.android.tools.r8.dex.Constants; | |
| import com.android.tools.r8.errors.Unreachable; | |
| import com.android.tools.r8.graph.DexField; | |
| import com.android.tools.r8.graph.DexItemFactory; | |
| import com.android.tools.r8.graph.DexMethod; | |
| import com.android.tools.r8.graph.DexType; | |
| import com.android.tools.r8.naming.MemberNaming.Signature.SignatureKind; | |
| import com.android.tools.r8.position.Position; | |
| import com.android.tools.r8.utils.DescriptorUtils; | |
| import com.android.tools.r8.utils.StringUtils; | |
| import java.io.IOException; | |
| import java.io.StringWriter; | |
| import java.io.Writer; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import org.objectweb.asm.Type; | |
| /** | |
| * Stores renaming information for a member. | |
| * | |
| * <p>This includes the signature and the original name. | |
| */ | |
| public class MemberNaming { | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (!(o instanceof MemberNaming)) { | |
| return false; | |
| } | |
| MemberNaming that = (MemberNaming) o; | |
| return signature.equals(that.signature) && renamedSignature.equals(that.renamedSignature); | |
| } | |
| @Override | |
| public int hashCode() { | |
| int result = signature.hashCode(); | |
| result = 31 * result + renamedSignature.hashCode(); | |
| return result; | |
| } | |
| /** Original signature of the member. */ | |
| final Signature signature; | |
| /** Renamed signature where the name (but not the types) have been renamed. */ | |
| final Signature renamedSignature; | |
| /** Position of the member in the file. */ | |
| final Position position; | |
| public MemberNaming(Signature signature, String renamedName) { | |
| this(signature, renamedName, Position.UNKNOWN); | |
| } | |
| public MemberNaming(Signature signature, String renamedName, Position position) { | |
| this.signature = signature; | |
| this.renamedSignature = signature.asRenamed(renamedName); | |
| this.position = position; | |
| } | |
| public Signature getOriginalSignature() { | |
| return signature; | |
| } | |
| public String getOriginalName() { | |
| return signature.name; | |
| } | |
| public Signature getRenamedSignature() { | |
| return renamedSignature; | |
| } | |
| public String getRenamedName() { | |
| return renamedSignature.name; | |
| } | |
| public boolean isMethodNaming() { | |
| return signature.kind() == SignatureKind.METHOD; | |
| } | |
| public boolean isFieldNaming() { | |
| return signature.kind() == SignatureKind.FIELD; | |
| } | |
| public Position getPosition() { | |
| return position; | |
| } | |
| @Override | |
| public String toString() { | |
| return signature.toString() + " -> " + renamedSignature.name; | |
| } | |
| public abstract static class Signature { | |
| public final String name; | |
| protected Signature(String name) { | |
| this.name = name; | |
| } | |
| abstract Signature asRenamed(String renamedName); | |
| abstract public SignatureKind kind(); | |
| @Override | |
| abstract public boolean equals(Object o); | |
| @Override | |
| abstract public int hashCode(); | |
| abstract void write(Writer builder) throws IOException; | |
| public boolean isQualified() { | |
| return name.indexOf(JAVA_PACKAGE_SEPARATOR) != -1; | |
| } | |
| public String toUnqualifiedName() { | |
| assert isQualified(); | |
| return name.substring(name.lastIndexOf(JAVA_PACKAGE_SEPARATOR) + 1); | |
| } | |
| public String toHolderFromQualified() { | |
| assert isQualified(); | |
| return name.substring(0, name.lastIndexOf(JAVA_PACKAGE_SEPARATOR)); | |
| } | |
| public boolean isMethodSignature() { | |
| return false; | |
| } | |
| public boolean isFieldSignature() { | |
| return false; | |
| } | |
| public MethodSignature asMethodSignature() { | |
| return null; | |
| } | |
| public FieldSignature asFieldSignature() { | |
| return null; | |
| } | |
| @Override | |
| public String toString() { | |
| try { | |
| StringWriter writer = new StringWriter(); | |
| write(writer); | |
| return writer.toString(); | |
| } catch (IOException e) { | |
| // StringWriter is not throwing IOException | |
| throw new Unreachable(e); | |
| } | |
| } | |
| enum SignatureKind { | |
| METHOD, | |
| FIELD | |
| } | |
| } | |
| public static class FieldSignature extends Signature { | |
| public final String type; | |
| public FieldSignature(String name, String type) { | |
| super(name); | |
| this.type = type; | |
| } | |
| public static FieldSignature fromDexField(DexField field) { | |
| return fromDexField(field, false); | |
| } | |
| public static FieldSignature fromDexField(DexField field, boolean withQualifiedName) { | |
| return new FieldSignature( | |
| withQualifiedName ? field.qualifiedName() : field.name.toSourceString(), | |
| field.type.toSourceString()); | |
| } | |
| public DexField toDexField(DexItemFactory factory, DexType clazz) { | |
| return factory.createField( | |
| clazz, | |
| factory.createType(javaTypeToDescriptor(type)), | |
| factory.createString(name)); | |
| } | |
| @Override | |
| Signature asRenamed(String renamedName) { | |
| return new FieldSignature(renamedName, type); | |
| } | |
| @Override | |
| public SignatureKind kind() { | |
| return SignatureKind.FIELD; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (!(o instanceof FieldSignature)) { | |
| return false; | |
| } | |
| FieldSignature that = (FieldSignature) o; | |
| return name.equals(that.name) && type.equals(that.type); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return name.hashCode() * 31 + type.hashCode(); | |
| } | |
| @Override | |
| public String toString() { | |
| return type + " " + name; | |
| } | |
| @Override | |
| void write(Writer writer) throws IOException { | |
| writer.append(type); | |
| writer.append(' '); | |
| writer.append(name); | |
| } | |
| @Override | |
| public boolean isFieldSignature() { | |
| return true; | |
| } | |
| @Override | |
| public FieldSignature asFieldSignature() { | |
| return this; | |
| } | |
| } | |
| public static class MethodSignature extends Signature { | |
| public final String type; | |
| public final String[] parameters; | |
| public MethodSignature(String name, String type, String[] parameters) { | |
| super(name); | |
| this.type = type; | |
| this.parameters = parameters; | |
| } | |
| public MethodSignature(String name, String type, Collection<String> parameters) { | |
| super(name); | |
| this.type = type; | |
| this.parameters = parameters.toArray(StringUtils.EMPTY_ARRAY); | |
| } | |
| public static MethodSignature fromDexMethod(DexMethod method) { | |
| return fromDexMethod(method, false); | |
| } | |
| public static MethodSignature fromDexMethod(DexMethod method, boolean withQualifiedName) { | |
| String[] paramNames = new String[method.getArity()]; | |
| DexType[] values = method.proto.parameters.values; | |
| for (int i = 0; i < values.length; i++) { | |
| paramNames[i] = values[i].toSourceString(); | |
| } | |
| return new MethodSignature( | |
| withQualifiedName ? method.qualifiedName() : method.name.toSourceString(), | |
| method.proto.returnType.toSourceString(), | |
| paramNames); | |
| } | |
| public static MethodSignature fromSignature(String name, String signature) { | |
| Type[] parameterDescriptors = Type.getArgumentTypes(signature); | |
| Type returnDescriptor = Type.getReturnType(signature); | |
| String[] parameterTypes = new String[parameterDescriptors.length]; | |
| for (int i = 0; i < parameterDescriptors.length; i++) { | |
| parameterTypes[i] = | |
| DescriptorUtils.descriptorToJavaType(parameterDescriptors[i].getDescriptor()); | |
| } | |
| return new MethodSignature( | |
| name, | |
| DescriptorUtils.descriptorToJavaType(returnDescriptor.getDescriptor()), | |
| parameterTypes); | |
| } | |
| public MethodSignature toUnqualified() { | |
| assert isQualified(); | |
| return new MethodSignature(toUnqualifiedName(), type, parameters); | |
| } | |
| public DexMethod toDexMethod(DexItemFactory factory, DexType clazz) { | |
| DexType[] paramTypes = new DexType[parameters.length]; | |
| for (int i = 0; i < parameters.length; i++) { | |
| paramTypes[i] = factory.createType(javaTypeToDescriptor(parameters[i])); | |
| } | |
| DexType returnType = factory.createType(javaTypeToDescriptor(type)); | |
| return factory.createMethod( | |
| clazz, | |
| factory.createProto(returnType, paramTypes), | |
| factory.createString(name)); | |
| } | |
| public static MethodSignature initializer(String[] parameters) { | |
| return new MethodSignature(Constants.INSTANCE_INITIALIZER_NAME, "void", parameters); | |
| } | |
| @Override | |
| Signature asRenamed(String renamedName) { | |
| return new MethodSignature(renamedName, type, parameters); | |
| } | |
| @Override | |
| public SignatureKind kind() { | |
| return SignatureKind.METHOD; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (!(o instanceof MethodSignature)) { | |
| return false; | |
| } | |
| MethodSignature that = (MethodSignature) o; | |
| return type.equals(that.type) | |
| && name.equals(that.name) | |
| && Arrays.equals(parameters, that.parameters); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return (type.hashCode() * 17 | |
| + name.hashCode()) * 31 | |
| + Arrays.hashCode(parameters); | |
| } | |
| @Override | |
| public String toString() { | |
| return type + ' ' + name + '(' + String.join(",", parameters) + ')'; | |
| } | |
| @Override | |
| void write(Writer writer) throws IOException { | |
| writer.append(type) | |
| .append(' ') | |
| .append(name) | |
| .append('('); | |
| for (int i = 0; i < parameters.length; i++) { | |
| writer.append(parameters[i]); | |
| if (i < parameters.length - 1) { | |
| writer.append(','); | |
| } | |
| } | |
| writer.append(')'); | |
| } | |
| public String toDescriptor() { | |
| StringBuilder sb = new StringBuilder(); | |
| sb.append('('); | |
| for (String parameterType : parameters) { | |
| sb.append(javaTypeToDescriptor(parameterType)); | |
| } | |
| sb.append(')'); | |
| sb.append(javaTypeToDescriptor(type)); | |
| return sb.toString(); | |
| } | |
| @Override | |
| public boolean isMethodSignature() { | |
| return true; | |
| } | |
| @Override | |
| public MethodSignature asMethodSignature() { | |
| return this; | |
| } | |
| } | |
| } |