| // 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.graph; |
| |
| 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.naming.NamingLens; |
| import com.android.tools.r8.utils.DescriptorUtils; |
| import java.util.List; |
| import java.util.function.Predicate; |
| |
| public class GenericSignaturePrinter implements GenericSignatureVisitor { |
| |
| private final NamingLens namingLens; |
| private final Predicate<DexType> isTypeMissing; |
| |
| public GenericSignaturePrinter(NamingLens namingLens, Predicate<DexType> isTypeMissing) { |
| this.namingLens = namingLens; |
| this.isTypeMissing = isTypeMissing; |
| } |
| |
| private final StringBuilder sb = new StringBuilder(); |
| |
| @Override |
| public ClassSignature visitClassSignature(ClassSignature classSignature) { |
| return classSignature.visit(this); |
| } |
| |
| @Override |
| public FieldTypeSignature visitFieldTypeSignature(FieldTypeSignature fieldSignature) { |
| printFieldTypeSignature(fieldSignature, false); |
| return fieldSignature; |
| } |
| |
| @Override |
| public MethodTypeSignature visitMethodSignature(MethodTypeSignature methodSignature) { |
| return methodSignature.visit(this); |
| } |
| |
| @Override |
| public List<TypeSignature> visitMethodTypeSignatures(List<TypeSignature> typeSignatures) { |
| sb.append("("); |
| typeSignatures.forEach(this::visitTypeSignature); |
| sb.append(")"); |
| return typeSignatures; |
| } |
| |
| @Override |
| public ReturnType visitReturnType(ReturnType returnType) { |
| if (returnType.isVoidDescriptor()) { |
| sb.append("V"); |
| } else { |
| visitTypeSignature(returnType.typeSignature); |
| } |
| return returnType; |
| } |
| |
| @Override |
| public List<TypeSignature> visitThrowsSignatures(List<TypeSignature> typeSignatures) { |
| for (TypeSignature typeSignature : typeSignatures) { |
| sb.append("^"); |
| visitTypeSignature(typeSignature); |
| } |
| return typeSignatures; |
| } |
| |
| @Override |
| public List<FormalTypeParameter> visitFormalTypeParameters( |
| List<FormalTypeParameter> formalTypeParameters) { |
| if (formalTypeParameters.isEmpty()) { |
| return formalTypeParameters; |
| } |
| sb.append("<"); |
| formalTypeParameters.forEach(this::visitFormalTypeParameter); |
| sb.append(">"); |
| return formalTypeParameters; |
| } |
| |
| @Override |
| public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) { |
| sb.append(":"); |
| printFieldTypeSignature(fieldSignature, false); |
| return fieldSignature; |
| } |
| |
| @Override |
| public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) { |
| if (fieldSignatures == null) { |
| return null; |
| } |
| fieldSignatures.forEach(this::visitInterfaceBound); |
| return fieldSignatures; |
| } |
| |
| @Override |
| public FieldTypeSignature visitInterfaceBound(FieldTypeSignature fieldSignature) { |
| sb.append(":"); |
| printFieldTypeSignature(fieldSignature, false); |
| return fieldSignature; |
| } |
| |
| @Override |
| public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) { |
| printFieldTypeSignature(classTypeSignature, false); |
| return classTypeSignature; |
| } |
| |
| @Override |
| public List<ClassTypeSignature> visitSuperInterfaces( |
| List<ClassTypeSignature> interfaceSignatures) { |
| interfaceSignatures.forEach(this::visitSuperInterface); |
| return interfaceSignatures; |
| } |
| |
| @Override |
| public ClassTypeSignature visitSuperInterface(ClassTypeSignature classTypeSignature) { |
| printFieldTypeSignature(classTypeSignature, false); |
| return classTypeSignature; |
| } |
| |
| @Override |
| public TypeSignature visitTypeSignature(TypeSignature typeSignature) { |
| if (typeSignature.isBaseTypeSignature()) { |
| DexType type = typeSignature.asBaseTypeSignature().type; |
| sb.append(type.toDescriptorString()); |
| } else { |
| printFieldTypeSignature(typeSignature.asFieldTypeSignature(), false); |
| } |
| return typeSignature; |
| } |
| |
| @Override |
| public ClassTypeSignature visitEnclosing( |
| ClassTypeSignature enclosingSignature, ClassTypeSignature enclosedSignature) { |
| printFieldTypeSignature(enclosingSignature, true); |
| return enclosingSignature; |
| } |
| |
| @Override |
| public List<FieldTypeSignature> visitTypeArguments( |
| DexType type, List<FieldTypeSignature> typeArguments) { |
| if (typeArguments.isEmpty()) { |
| return typeArguments; |
| } |
| sb.append("<"); |
| for (FieldTypeSignature typeArgument : typeArguments) { |
| WildcardIndicator wildcardIndicator = typeArgument.getWildcardIndicator(); |
| if (wildcardIndicator != WildcardIndicator.NONE) { |
| assert wildcardIndicator != WildcardIndicator.NOT_AN_ARGUMENT; |
| sb.append(wildcardIndicator == WildcardIndicator.POSITIVE ? "+" : "-"); |
| } |
| visitTypeSignature(typeArgument); |
| } |
| sb.append(">"); |
| return typeArguments; |
| } |
| |
| @Override |
| public FormalTypeParameter visitFormalTypeParameter(FormalTypeParameter formalTypeParameter) { |
| sb.append(formalTypeParameter.name); |
| return formalTypeParameter.visit(this); |
| } |
| |
| private void printFieldTypeSignature( |
| FieldTypeSignature fieldTypeSignature, boolean printingOuter) { |
| // For inner member classes we only print the inner name and the type-arguments. |
| if (fieldTypeSignature.isStar()) { |
| sb.append("*"); |
| } else if (fieldTypeSignature.isTypeVariableSignature()) { |
| sb.append("T").append(fieldTypeSignature.asTypeVariableSignature().typeVariable).append(";"); |
| } else if (fieldTypeSignature.isArrayTypeSignature()) { |
| sb.append("["); |
| fieldTypeSignature.asArrayTypeSignature().visit(this); |
| } else { |
| assert fieldTypeSignature.isClassTypeSignature(); |
| ClassTypeSignature classTypeSignature = fieldTypeSignature.asClassTypeSignature(); |
| if (classTypeSignature.hasNoSignature()) { |
| return; |
| } |
| // Visit enclosing before printing the type name to ensure we |
| if (classTypeSignature.enclosingTypeSignature != null) { |
| visitEnclosing(classTypeSignature.enclosingTypeSignature, classTypeSignature); |
| } |
| String renamedString = namingLens.lookupDescriptor(classTypeSignature.type).toString(); |
| if (classTypeSignature.enclosingTypeSignature == null) { |
| sb.append("L").append(DescriptorUtils.getBinaryNameFromDescriptor(renamedString)); |
| } else { |
| DexType enclosingType = classTypeSignature.enclosingTypeSignature.type; |
| String outerDescriptor = namingLens.lookupDescriptor(enclosingType).toString(); |
| String innerClassName = DescriptorUtils.getInnerClassName(outerDescriptor, renamedString); |
| if (innerClassName == null && isTypeMissing.test(classTypeSignature.type)) { |
| assert renamedString.equals(classTypeSignature.type.toDescriptorString()); |
| innerClassName = |
| DescriptorUtils.getInnerClassName(enclosingType.toDescriptorString(), renamedString); |
| } |
| if (innerClassName == null) { |
| // We can no longer encode the inner name in the generic signature. |
| return; |
| } |
| sb.append(".").append(innerClassName); |
| } |
| visitTypeArguments(null, classTypeSignature.typeArguments); |
| if (!printingOuter) { |
| sb.append(";"); |
| } |
| } |
| } |
| |
| @Override |
| public DexType visitType(DexType type) { |
| // We need to delay printing of class type until enclosing class has been visited. We therefore |
| // only print in printFieldTypeSignature. |
| return type; |
| } |
| |
| @Override |
| public String toString() { |
| return sb.toString(); |
| } |
| } |