All Downloads are FREE. Search and download functionalities are using the official Maven repository.

proguard.classfile.util.ClassReferenceInitializer Maven / Gradle / Ivy

/*
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
 *             of Java bytecode.
 *
 * Copyright (c) 2002-2019 Guardsquare NV
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package proguard.classfile.util;

import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.visitor.*;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.kotlin.*;
import proguard.classfile.kotlin.visitors.*;
import proguard.classfile.visitor.*;

import java.util.*;
import java.util.stream.Collectors;

import static proguard.classfile.ClassConstants.INNER_CLASS_SEPARATOR;

/**
 * This ClassVisitor initializes the references of all classes that
 * it visits.
 * 

* All class constant pool entries get direct references to the corresponding * classes. These references make it more convenient to travel up and across * the class hierarchy. *

* All field and method reference constant pool entries get direct references * to the corresponding classes, fields, and methods. *

* All name and type constant pool entries get a list of direct references to * the classes listed in the type. *

* All Kotlin metadata elements get references to their corresponding Java * implementation elements. *

* This visitor optionally prints warnings if some items can't be found. *

* The class hierarchy must be initialized before using this visitor. * * @author Eric Lafortune */ public class ClassReferenceInitializer extends SimplifiedVisitor implements ClassVisitor, // Implementation interfaces. MemberVisitor, ConstantVisitor, AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, AnnotationVisitor, ElementValueVisitor { private final ClassPool programClassPool; private final ClassPool libraryClassPool; private WarningPrinter missingClassWarningPrinter; private final WarningPrinter missingProgramMemberWarningPrinter; private final WarningPrinter missingLibraryMemberWarningPrinter; private final WarningPrinter dependencyWarningPrinter; private final MemberFinder memberFinder = new MemberFinder(); private final MemberFinder strictMemberFinder = new MemberFinder(false); private final KotlinReferenceInitializer kotlinReferenceInitializer = new KotlinReferenceInitializer(); /** * Creates a new ClassReferenceInitializer that initializes the references * of all visited class files. */ public ClassReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool) { this(programClassPool, libraryClassPool, null, null, null, null); } /** * Creates a new ClassReferenceInitializer that initializes the references * of all visited class files, optionally printing warnings if some classes * or class members can't be found or if they are in the program class pool. */ public ClassReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool, WarningPrinter missingClassWarningPrinter, WarningPrinter missingProgramMemberWarningPrinter, WarningPrinter missingLibraryMemberWarningPrinter, WarningPrinter dependencyWarningPrinter) { this.programClassPool = programClassPool; this.libraryClassPool = libraryClassPool; this.missingClassWarningPrinter = missingClassWarningPrinter; this.missingProgramMemberWarningPrinter = missingProgramMemberWarningPrinter; this.missingLibraryMemberWarningPrinter = missingLibraryMemberWarningPrinter; this.dependencyWarningPrinter = dependencyWarningPrinter; } // Implementations for ClassVisitor. public void visitProgramClass(ProgramClass programClass) { // Initialize the constant pool entries. programClass.constantPoolEntriesAccept(this); // Initialize all fields and methods. programClass.fieldsAccept(this); programClass.methodsAccept(this); // Initialize the attributes. programClass.attributesAccept(this); // Initialize the Kotlin metadata. programClass.kotlinMetadataAccept(kotlinReferenceInitializer); } public void visitLibraryClass(LibraryClass libraryClass) { // Initialize all fields and methods. libraryClass.fieldsAccept(this); libraryClass.methodsAccept(this); // Initialize the Kotlin metadata. libraryClass.kotlinMetadataAccept(kotlinReferenceInitializer); } // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) { programField.referencedClass = findReferencedClass(programClass, programField.getDescriptor(programClass)); // Initialize the attributes. programField.attributesAccept(programClass, this); } public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) { programMethod.referencedClasses = findReferencedClasses(programClass, programMethod.getDescriptor(programClass)); // Initialize the attributes. programMethod.attributesAccept(programClass, this); } public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) { libraryField.referencedClass = findReferencedClass(libraryClass, libraryField.getDescriptor(libraryClass)); } public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) { libraryMethod.referencedClasses = findReferencedClasses(libraryClass, libraryMethod.getDescriptor(libraryClass)); } // Implementations for ConstantVisitor. public void visitAnyConstant(Clazz clazz, Constant constant) {} public void visitStringConstant(Clazz clazz, StringConstant stringConstant) { // Fill out the String class. stringConstant.javaLangStringClass = findClass(clazz, ClassConstants.NAME_JAVA_LANG_STRING); } public void visitDynamicConstant(Clazz clazz, DynamicConstant dynamicConstant) { dynamicConstant.referencedClasses = findReferencedClasses(clazz, dynamicConstant.getType(clazz)); } public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) { invokeDynamicConstant.referencedClasses = findReferencedClasses(clazz, invokeDynamicConstant.getType(clazz)); } public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) { // Fill out the MethodHandle class. methodHandleConstant.javaLangInvokeMethodHandleClass = findClass(clazz, ClassConstants.NAME_JAVA_LANG_INVOKE_METHOD_HANDLE); } public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { String className = refConstant.getClassName(clazz); // Methods for array types should be found in the Object class. if (ClassUtil.isInternalArrayType(className)) { className = ClassConstants.NAME_JAVA_LANG_OBJECT; } // See if we can find the referenced class. // Unresolved references are assumed to refer to library classes // that will not change anyway. Clazz referencedClass = findClass(clazz, className); if (referencedClass != null) { String name = refConstant.getName(clazz); String type = refConstant.getType(clazz); boolean isFieldRef = refConstant.getTag() == ClassConstants.CONSTANT_Fieldref; // See if we can find the referenced class member somewhere in the // hierarchy. refConstant.referencedMember = memberFinder.findMember(clazz, referencedClass, name, type, isFieldRef); refConstant.referencedClass = memberFinder.correspondingClass(); if (refConstant.referencedMember == null) { // We haven't found the class member anywhere in the hierarchy. boolean isProgramClass = referencedClass instanceof ProgramClass; WarningPrinter missingMemberWarningPrinter = isProgramClass ? missingProgramMemberWarningPrinter : missingLibraryMemberWarningPrinter; if (missingMemberWarningPrinter != null) { missingMemberWarningPrinter.print(clazz.getName(), className, "Warning: " + ClassUtil.externalClassName(clazz.getName()) + ": can't find referenced " + (isFieldRef ? "field '" + ClassUtil.externalFullFieldDescription(0, name, type) : "method '" + ClassUtil.externalFullMethodDescription(className, 0, name, type)) + "' in " + (isProgramClass ? "program" : "library") + " class " + ClassUtil.externalClassName(className)); } } } } public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Fill out the referenced class. classConstant.referencedClass = findClass(clazz, ClassUtil.internalClassNameFromClassType(classConstant.getName(clazz))); // Fill out the Class class. classConstant.javaLangClassClass = findClass(clazz, ClassConstants.NAME_JAVA_LANG_CLASS); } public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { // Fill out the MethodType class. methodTypeConstant.javaLangInvokeMethodTypeClass = findClass(clazz, ClassConstants.NAME_JAVA_LANG_INVOKE_METHOD_TYPE); methodTypeConstant.referencedClasses = findReferencedClasses(clazz, methodTypeConstant.getType(clazz)); } // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) { String enclosingClassName = enclosingMethodAttribute.getClassName(clazz); // See if we can find the referenced class. enclosingMethodAttribute.referencedClass = findClass(clazz, enclosingClassName); if (enclosingMethodAttribute.referencedClass != null) { // Is there an enclosing method? Otherwise it's just initialization // code outside of the constructors. if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) { String name = enclosingMethodAttribute.getName(clazz); String type = enclosingMethodAttribute.getType(clazz); // See if we can find the method in the referenced class. enclosingMethodAttribute.referencedMethod = enclosingMethodAttribute.referencedClass.findMethod(name, type); if (enclosingMethodAttribute.referencedMethod == null && missingProgramMemberWarningPrinter != null) { // We couldn't find the enclosing method. String className = clazz.getName(); missingProgramMemberWarningPrinter.print(className, enclosingClassName, "Warning: " + ClassUtil.externalClassName(className) + ": can't find enclosing method '" + ClassUtil.externalFullMethodDescription(enclosingClassName, 0, name, type) + "' in program class " + ClassUtil.externalClassName(enclosingClassName)); } } } else { if (enclosingClassName != null && enclosingClassName.indexOf(INNER_CLASS_SEPARATOR) != -1) { String myEnclosingClassName = enclosingClassName; do { // [DGD-1462] Truncate the name until we find the first // non-anonymous class, i.e. the first class that exists in // a class pool. myEnclosingClassName = myEnclosingClassName.substring(0, myEnclosingClassName.lastIndexOf(INNER_CLASS_SEPARATOR)); enclosingMethodAttribute.referencedClass = findClass(clazz, myEnclosingClassName, false); } while (enclosingMethodAttribute.referencedClass == null && myEnclosingClassName.indexOf(INNER_CLASS_SEPARATOR) != -1); if (enclosingMethodAttribute.referencedClass == null) { reportMissingClass(clazz.getName(), enclosingClassName); } } } } public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { // Initialize the nested attributes. codeAttribute.attributesAccept(clazz, method, this); } public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { // Initialize the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { // Initialize the local variable types. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { signatureAttribute.referencedClasses = findReferencedClasses(clazz, signatureAttribute.getSignature(clazz)); } public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) { // Initialize the annotations. annotationsAttribute.annotationsAccept(clazz, this); } public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) { // Initialize the annotations. parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) { // Initialize the annotation. annotationDefaultAttribute.defaultValueAccept(clazz, this); } // Implementations for LocalVariableInfoVisitor. public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { localVariableInfo.referencedClass = findReferencedClass(clazz, localVariableInfo.getDescriptor(clazz)); } // Implementations for LocalVariableTypeInfoVisitor. public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { localVariableTypeInfo.referencedClasses = findReferencedClasses(clazz, localVariableTypeInfo.getSignature(clazz)); } // Implementations for AnnotationVisitor. public void visitAnnotation(Clazz clazz, Annotation annotation) { annotation.referencedClasses = findReferencedClasses(clazz, annotation.getType(clazz)); // Initialize the element values. annotation.elementValuesAccept(clazz, this); } // Implementations for ElementValueVisitor. public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) { initializeElementValue(clazz, annotation, constantElementValue); } public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) { initializeElementValue(clazz, annotation, enumConstantElementValue); enumConstantElementValue.referencedClasses = findReferencedClasses(clazz, enumConstantElementValue.getTypeName(clazz)); } public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) { initializeElementValue(clazz, annotation, classElementValue); classElementValue.referencedClasses = findReferencedClasses(clazz, classElementValue.getClassName(clazz)); } public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) { initializeElementValue(clazz, annotation, annotationElementValue); // Initialize the annotation. annotationElementValue.annotationAccept(clazz, this); } public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) { initializeElementValue(clazz, annotation, arrayElementValue); // Initialize the element values. arrayElementValue.elementValuesAccept(clazz, annotation, this); } /** * Initializes the referenced method of an element value, if any. */ private void initializeElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) { // See if we have a referenced class. if (annotation != null && annotation.referencedClasses != null && elementValue.u2elementNameIndex != 0) { // See if we can find the method in the referenced class // (ignoring the descriptor). String name = elementValue.getMethodName(clazz); Clazz referencedClass = annotation.referencedClasses[0]; elementValue.referencedClass = referencedClass; elementValue.referencedMethod = referencedClass.findMethod(name, null); } } // Kotlin initializer class, used to initialize Kotlin metadata references. private class KotlinReferenceInitializer implements KotlinMetadataVisitor, KotlinPropertyVisitor, KotlinFunctionVisitor, KotlinConstructorVisitor, KotlinTypeVisitor, KotlinTypeAliasVisitor, KotlinValueParameterVisitor, KotlinTypeParameterVisitor { // Implementations for KotlinMetadataVisitor. @Override public void visitAnyKotlinMetadata(Clazz clazz, KotlinMetadata kotlinMetadata) {} @Override public void visitKotlinDeclarationContainerMetadata(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata) { kotlinDeclarationContainerMetadata.ownerClassName = clazz.getName(); kotlinDeclarationContainerMetadata.ownerReferencedClass = findClass(clazz, kotlinDeclarationContainerMetadata.ownerClassName); kotlinDeclarationContainerMetadata.propertiesAccept( clazz, this); kotlinDeclarationContainerMetadata.delegatedPropertiesAccept(clazz, this); kotlinDeclarationContainerMetadata.functionsAccept( clazz, this); kotlinDeclarationContainerMetadata.typeAliasesAccept( clazz,this); } @Override public void visitKotlinClassMetadata(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata) { kotlinClassKindMetadata.referencedClass = findClass(clazz, kotlinClassKindMetadata.className); if (kotlinClassKindMetadata.anonymousObjectOriginName != null) { kotlinClassKindMetadata.anonymousObjectOriginClass = findClass(clazz, kotlinClassKindMetadata.anonymousObjectOriginName, false); if (kotlinClassKindMetadata.anonymousObjectOriginClass == null) { kotlinClassKindMetadata.anonymousObjectOriginName = null; } } //TODO strip prefix from companion and nested classes. if (kotlinClassKindMetadata.companionObjectName != null) { String name = clazz.getName() + "$" + kotlinClassKindMetadata.companionObjectName; kotlinClassKindMetadata.referencedCompanionClass = findClass(clazz, name); kotlinClassKindMetadata.referencedCompanionField = memberFinder.findField(clazz, kotlinClassKindMetadata.companionObjectName, ClassUtil.internalTypeFromClassName(name)); } kotlinClassKindMetadata.referencedEnumEntries = kotlinClassKindMetadata.enumEntryNames .stream() .map(enumEntry -> strictMemberFinder.findField(clazz, enumEntry, null)) .collect(Collectors.toList()); kotlinClassKindMetadata.referencedNestedClasses = kotlinClassKindMetadata.nestedClassNames .stream() .map(nestedName -> findClass(clazz, clazz.getName() + "$" + nestedName)) .collect(Collectors.toList()); kotlinClassKindMetadata.referencedSealedSubClasses= kotlinClassKindMetadata.sealedSubclassNames .stream() .map(sealedSubName -> findClass(clazz, sealedSubName)) .collect(Collectors.toList()); kotlinClassKindMetadata.typeParametersAccept(clazz, this); kotlinClassKindMetadata.superTypesAccept( clazz, this); kotlinClassKindMetadata.constructorsAccept( clazz, this); visitKotlinDeclarationContainerMetadata(clazz, kotlinClassKindMetadata); } @Override public void visitKotlinFileFacadeMetadata(Clazz clazz, KotlinFileFacadeKindMetadata kotlinFileFacadeKindMetadata) { visitKotlinDeclarationContainerMetadata(clazz, kotlinFileFacadeKindMetadata); } @Override public void visitKotlinSyntheticClassMetadata(Clazz clazz, KotlinSyntheticClassKindMetadata kotlinSyntheticClassKindMetadata) { kotlinSyntheticClassKindMetadata.className = clazz.getName(); kotlinSyntheticClassKindMetadata.referencedClass = clazz; kotlinSyntheticClassKindMetadata.functionsAccept(clazz, this); } @Override public void visitKotlinMultiFileFacadeMetadata(Clazz clazz, KotlinMultiFileFacadeKindMetadata kotlinMultiFileFacadeKindMetadata) { kotlinMultiFileFacadeKindMetadata.referencedPartClasses = kotlinMultiFileFacadeKindMetadata.partClassNames .stream() .map(partName -> findClass(clazz, partName)) .collect(Collectors.toList()); } @Override public void visitKotlinMultiFilePartMetadata(Clazz clazz, KotlinMultiFilePartKindMetadata kotlinMultiFilePartKindMetadata) { kotlinMultiFilePartKindMetadata.referencedFacade = findClass(clazz, kotlinMultiFilePartKindMetadata.facadeName); visitKotlinDeclarationContainerMetadata(clazz, kotlinMultiFilePartKindMetadata); } // Implementations for KotlinPropertyVisitor. @Override public void visitAnyProperty(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata, KotlinPropertyMetadata kotlinPropertyMetadata) { if (kotlinPropertyMetadata.backingFieldSignature != null) { kotlinPropertyMetadata.referencedBackingField = strictMemberFinder.findField(clazz, kotlinPropertyMetadata.backingFieldSignature.getName(), kotlinPropertyMetadata.backingFieldSignature.getDesc()); kotlinPropertyMetadata.referencedBackingFieldClass = strictMemberFinder.correspondingClass(); } if (kotlinPropertyMetadata.getterSignature != null) //TODO kotlinPropertyMetadata.hasGetter() { kotlinPropertyMetadata.referencedGetterMethod = strictMemberFinder.findMethod(clazz, kotlinPropertyMetadata.getterSignature.getName(), kotlinPropertyMetadata.getterSignature.getDesc()); } if (kotlinPropertyMetadata.setterSignature != null) //TODO kotlinPropertyMetadata.hasSetter() { kotlinPropertyMetadata.referencedSetterMethod = strictMemberFinder.findMethod(clazz, kotlinPropertyMetadata.setterSignature.getName(), kotlinPropertyMetadata.setterSignature.getDesc()); } if (kotlinPropertyMetadata.syntheticMethodForAnnotations != null) { kotlinPropertyMetadata.referencedSyntheticMethodForAnnotations = strictMemberFinder.findMethod(clazz, kotlinPropertyMetadata.syntheticMethodForAnnotations.getName(), kotlinPropertyMetadata.syntheticMethodForAnnotations.getDesc()); kotlinPropertyMetadata.referencedSyntheticMethodClass = strictMemberFinder.correspondingClass(); } kotlinPropertyMetadata.typeParametersAccept( clazz, kotlinDeclarationContainerMetadata, this); kotlinPropertyMetadata.receiverTypeAccept( clazz, kotlinDeclarationContainerMetadata, this); kotlinPropertyMetadata.typeAccept( clazz, kotlinDeclarationContainerMetadata, this); kotlinPropertyMetadata.setterParametersAccept(clazz, kotlinDeclarationContainerMetadata, this); } // Implementations for KotlinFunctionVisitor. @Override public void visitAnyFunction(Clazz clazz, KotlinMetadata kotlinMetadata, KotlinFunctionMetadata kotlinFunctionMetadata) { kotlinFunctionMetadata.referencedMethodClass = clazz; if (kotlinFunctionMetadata.jvmSignature != null) { kotlinFunctionMetadata.referencedMethod = strictMemberFinder.findMethod(kotlinFunctionMetadata.referencedMethodClass, kotlinFunctionMetadata.jvmSignature.getName(), kotlinFunctionMetadata.jvmSignature.getDesc()); } if (kotlinFunctionMetadata.lambdaClassOriginName != null) { kotlinFunctionMetadata.referencedLambdaClassOrigin = findClass(clazz, kotlinFunctionMetadata.lambdaClassOriginName, false); if (kotlinFunctionMetadata.referencedLambdaClassOrigin == null) { kotlinFunctionMetadata.lambdaClassOriginName = null; } } kotlinFunctionMetadata.contractsAccept( clazz, kotlinMetadata, new AllTypeVisitor(this)); kotlinFunctionMetadata.typeParametersAccept( clazz, kotlinMetadata, this); kotlinFunctionMetadata.receiverTypeAccept( clazz, kotlinMetadata, this); kotlinFunctionMetadata.valueParametersAccept(clazz, kotlinMetadata, this); kotlinFunctionMetadata.returnTypeAccept( clazz, kotlinMetadata, this); } // Implementations for KotlinConstructorVisitor @Override public void visitConstructor(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata, KotlinConstructorMetadata kotlinConstructorMetadata) { // Annotation constructors don't have a corresponding constructor method. if (kotlinConstructorMetadata.jvmSignature != null) { kotlinConstructorMetadata.referencedMethod = strictMemberFinder.findMethod(clazz, kotlinConstructorMetadata.jvmSignature.getName(), kotlinConstructorMetadata.jvmSignature.getDesc()); } kotlinConstructorMetadata.valueParametersAccept(clazz, kotlinClassKindMetadata, this); } // Implementations for KotlinTypeVisitor. @Override public void visitAnyType(Clazz clazz, KotlinTypeMetadata kotlinTypeMetadata) { String className = kotlinTypeMetadata.className; if (className != null) { // If this is a dummy Kotlin type, assign a dummy referenced class. kotlinTypeMetadata.referencedClass = KotlinConstants.dummyClassPool.getClass(className); if (kotlinTypeMetadata.referencedClass == null) { kotlinTypeMetadata.referencedClass = findClass(clazz, className); } } else if (kotlinTypeMetadata.aliasName != null) { // This type is an alias, that refers to an actual type (or another alias). // We search for the alias definition to create a reference for this use. String aliasName = kotlinTypeMetadata.aliasName; int innerClassMarkerIndex = aliasName.lastIndexOf('.'); String classNameFilter, simpleName; if (innerClassMarkerIndex != -1) { // Declared inside a class - we know exactly which one. classNameFilter = aliasName.substring(0, innerClassMarkerIndex); simpleName = aliasName.substring(innerClassMarkerIndex + 1); } else { // Declared in a file facade - we know which package only. classNameFilter = ClassUtil.internalPackagePrefix(aliasName) + "*"; simpleName = ClassUtil.internalSimpleClassName(kotlinTypeMetadata.aliasName); } programClassPool.classesAccept( classNameFilter, new ReferencedKotlinMetadataVisitor( new KotlinTypeAliasReferenceInitializer(kotlinTypeMetadata, simpleName)) ); } initializeAnnotations(clazz, kotlinTypeMetadata.annotations); kotlinTypeMetadata.typeArgumentsAccept(clazz, this); kotlinTypeMetadata.outerClassAccept( clazz, this); kotlinTypeMetadata.upperBoundsAccept( clazz, this); kotlinTypeMetadata.abbreviationAccept( clazz, this); } // Implementations for KotlinTypeAliasVisitor. @Override public void visitTypeAlias(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata, KotlinTypeAliasMetadata kotlinTypeAliasMetadata) { initializeAnnotations(clazz, kotlinTypeAliasMetadata.annotations); kotlinTypeAliasMetadata.referencedDeclarationContainer = kotlinDeclarationContainerMetadata; kotlinTypeAliasMetadata.underlyingTypeAccept(clazz, kotlinDeclarationContainerMetadata, this); kotlinTypeAliasMetadata.expandedTypeAccept( clazz, kotlinDeclarationContainerMetadata, this); kotlinTypeAliasMetadata.typeParametersAccept(clazz, kotlinDeclarationContainerMetadata, this); } // Implementations for KotlinValueParameterVisitor. @Override public void visitAnyValueParameter(Clazz clazz, KotlinValueParameterMetadata kotlinValueParameterMetadata) {} @Override public void visitFunctionValParameter(Clazz clazz, KotlinMetadata kotlinMetadata, KotlinFunctionMetadata kotlinFunctionMetadata, KotlinValueParameterMetadata kotlinValueParameterMetadata) { kotlinValueParameterMetadata.typeAccept(clazz, kotlinMetadata, kotlinFunctionMetadata, this); } @Override public void visitConstructorValParameter(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata, KotlinConstructorMetadata kotlinConstructorMetadata, KotlinValueParameterMetadata kotlinValueParameterMetadata) { kotlinValueParameterMetadata.typeAccept(clazz, kotlinClassKindMetadata, kotlinConstructorMetadata, this); } @Override public void visitPropertyValParameter(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata, KotlinPropertyMetadata kotlinPropertyMetadata, KotlinValueParameterMetadata kotlinValueParameterMetadata) { kotlinValueParameterMetadata.typeAccept(clazz, kotlinDeclarationContainerMetadata, kotlinPropertyMetadata, this); } // Implementations for KotlinTypeParameterVisitor @Override public void visitAnyTypeParameter(Clazz clazz, KotlinTypeParameterMetadata kotlinTypeParameterMetadata) { initializeAnnotations(clazz, kotlinTypeParameterMetadata.annotations); kotlinTypeParameterMetadata.upperBoundsAccept(clazz, this); } /** * Initialize Kotlin annotations. */ private void initializeAnnotations(Clazz clazz, List annotations) { for (KotlinMetadataAnnotation annotation : annotations) { annotation.referencedAnnotationClass = findClass(clazz, annotation.kmAnnotation.getClassName()); if (annotation.referencedAnnotationClass != null) { Set argumentNames = annotation.kmAnnotation.getArguments().keySet(); Map referencedKeys = new HashMap(); for (String argumentName : argumentNames) { referencedKeys.put(argumentName, strictMemberFinder.findMethod(annotation.referencedAnnotationClass, argumentName, null)); } annotation.referencedArgumentMethods = referencedKeys; } else { annotation.referencedArgumentMethods = new HashMap<>(); } } } } // Small utility methods. /** * Returns the single class referenced by the given descriptor, or * null if there isn't any useful reference. */ private Clazz findReferencedClass(Clazz referencingClass, String descriptor) { DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); enumeration.nextFluff(); if (enumeration.hasMoreClassNames()) { return findClass(referencingClass, enumeration.nextClassName()); } return null; } /** * Returns an array of classes referenced by the given descriptor, or * null if there aren't any useful references. */ private Clazz[] findReferencedClasses(Clazz referencingClass, String descriptor) { DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); int classCount = enumeration.classCount(); if (classCount > 0) { Clazz[] referencedClasses = new Clazz[classCount]; boolean foundReferencedClasses = false; for (int index = 0; index < classCount; index++) { String fluff = enumeration.nextFluff(); String name = enumeration.nextClassName(); Clazz referencedClass = findClass(referencingClass, name); if (referencedClass != null) { referencedClasses[index] = referencedClass; foundReferencedClasses = true; } } if (foundReferencedClasses) { return referencedClasses; } } return null; } /** * Returns the class with the given name, either for the program class pool * or from the library class pool, or null if it can't be found. */ private Clazz findClass(Clazz referencingClass, String name) { return findClass(referencingClass, name, true); } /** * @param report Report if the class is not found. Set to false if the class * doesn't necessarily exist. */ private Clazz findClass(Clazz referencingClass, String name, boolean report) { // Is it an array type? if (ClassUtil.isInternalArrayType(name)) { // Ignore any primitive array types. if (!ClassUtil.isInternalClassType(name)) { return null; } // Strip the array part. name = ClassUtil.internalClassNameFromClassType(name); } // First look for the class in the program class pool. Clazz clazz = programClassPool.getClass(name); // Otherwise look for the class in the library class pool. if (clazz == null) { clazz = libraryClassPool.getClass(name); if (report && clazz == null && missingClassWarningPrinter != null) { // We didn't find the superclass or interface. Print a warning. reportMissingClass(referencingClass.getName(), name); } } else if (dependencyWarningPrinter != null) { // The superclass or interface was found in the program class pool. // Print a warning. String referencingClassName = referencingClass.getName(); dependencyWarningPrinter.print(referencingClassName, name, "Warning: library class " + ClassUtil.externalClassName(referencingClassName) + " depends on program class " + ClassUtil.externalClassName(name)); } return clazz; } private void reportMissingClass(String referencingClassName, String name) { missingClassWarningPrinter.print(referencingClassName, name, "Warning: " + ClassUtil.externalClassName(referencingClassName) + ": can't find referenced class " + ClassUtil.externalClassName(name)); } // Helper class for KotlinReferenceInitializer. public static class KotlinTypeAliasReferenceInitializer implements KotlinMetadataVisitor, KotlinTypeAliasVisitor { private final KotlinTypeMetadata kotlinTypeMetadata; private final String simpleName; KotlinTypeAliasReferenceInitializer(KotlinTypeMetadata kotlinTypeMetadata, String simpleName) { this.simpleName = simpleName; this.kotlinTypeMetadata = kotlinTypeMetadata; } // Implementations for KotlinMetadataVisitor. @Override public void visitAnyKotlinMetadata(Clazz clazz, KotlinMetadata kotlinMetadata) {} @Override public void visitKotlinDeclarationContainerMetadata(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata) { kotlinDeclarationContainerMetadata.typeAliasesAccept(clazz, this); } @Override public void visitKotlinClassMetadata(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata) { // Only if the alias was declared inside this class. if (kotlinTypeMetadata.aliasName.equals(clazz.getName() + "." + simpleName)) { kotlinClassKindMetadata.typeAliasesAccept(clazz, this); } } // Implementations for KotlinTypeAliasVisitor. @Override public void visitTypeAlias(Clazz clazz, KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata, KotlinTypeAliasMetadata kotlinTypeAliasMetadata) { if (this.simpleName.equals(kotlinTypeAliasMetadata.name)) { this.kotlinTypeMetadata.referencedTypeAlias = kotlinTypeAliasMetadata; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy