Add ReplaceWithSupertypeAnonymousTypeTransformer to light analysis tests
To make these tests behave closer to kapt, since kapt is the primary use case for the light analysis mode. AbstractLightAnalysisModeTest compares the text dump of bytecode obtained with full analysis and light analysis, removing things like anonymous/synthetic entities. In the light analysis mode anonymous objects in supertypes are always approximated, and in the full analysis mode they are always present as is in signatures. So we're transforming the text dump in the same way, by approximating anonymous objects in signatures (more precisely, in return types of methods and fields) to the supertype.
This commit is contained in:
+40
-12
@@ -11,11 +11,11 @@ import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
|
||||
class BytecodeListingTextCollectingVisitor(
|
||||
val filter: Filter,
|
||||
val allClasses: Map<Type, ClassNode>,
|
||||
val withSignatures: Boolean,
|
||||
api: Int = Opcodes.API_VERSION,
|
||||
val withAnnotations: Boolean = true,
|
||||
val sortDeclarations: Boolean = true,
|
||||
) : ClassVisitor(api) {
|
||||
) : ClassVisitor(Opcodes.API_VERSION) {
|
||||
companion object {
|
||||
@JvmOverloads
|
||||
fun getText(
|
||||
@@ -23,18 +23,27 @@ class BytecodeListingTextCollectingVisitor(
|
||||
filter: Filter = Filter.EMPTY,
|
||||
withSignatures: Boolean = false,
|
||||
withAnnotations: Boolean = true,
|
||||
sortDeclarations: Boolean = true
|
||||
) = factory.getClassFiles()
|
||||
.sortedBy { it.relativePath }
|
||||
.mapNotNull {
|
||||
val cr = ClassReader(it.asByteArray())
|
||||
val node = ClassNode(Opcodes.API_VERSION)
|
||||
cr.accept(node, ClassReader.SKIP_CODE)
|
||||
val visitor = BytecodeListingTextCollectingVisitor(filter, withSignatures, withAnnotations = withAnnotations, sortDeclarations = sortDeclarations)
|
||||
sortDeclarations: Boolean = true,
|
||||
): String {
|
||||
val classes = factory.getClassFiles()
|
||||
.sortedBy { it.relativePath }
|
||||
.map {
|
||||
ClassNode(Opcodes.API_VERSION).also { node ->
|
||||
ClassReader(it.asByteArray()).accept(node, ClassReader.SKIP_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
val allClasses = classes.associateBy { Type.getObjectType(it.name) }
|
||||
|
||||
return classes.mapNotNull { node ->
|
||||
val visitor = BytecodeListingTextCollectingVisitor(
|
||||
filter, allClasses, withSignatures, withAnnotations = withAnnotations, sortDeclarations = sortDeclarations
|
||||
)
|
||||
node.accept(visitor)
|
||||
|
||||
if (!filter.shouldWriteClass(node)) null else visitor.text
|
||||
}.joinToString("\n\n", postfix = "\n")
|
||||
}
|
||||
|
||||
private val CLASS_OR_FIELD_OR_METHOD = setOf(ModifierTarget.CLASS, ModifierTarget.FIELD, ModifierTarget.METHOD)
|
||||
private val CLASS_OR_METHOD = setOf(ModifierTarget.CLASS, ModifierTarget.METHOD)
|
||||
@@ -69,12 +78,14 @@ class BytecodeListingTextCollectingVisitor(
|
||||
fun shouldWriteMethod(access: Int, name: String, desc: String): Boolean
|
||||
fun shouldWriteField(access: Int, name: String, desc: String): Boolean
|
||||
fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?): Boolean
|
||||
val shouldTransformAnonymousTypes: Boolean
|
||||
|
||||
object EMPTY : Filter {
|
||||
override fun shouldWriteClass(node: ClassNode) = true
|
||||
override fun shouldWriteMethod(access: Int, name: String, desc: String) = true
|
||||
override fun shouldWriteField(access: Int, name: String, desc: String) = true
|
||||
override fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?) = true
|
||||
override val shouldTransformAnonymousTypes: Boolean get() = false
|
||||
}
|
||||
|
||||
object ForCodegenTests : Filter {
|
||||
@@ -82,6 +93,7 @@ class BytecodeListingTextCollectingVisitor(
|
||||
override fun shouldWriteMethod(access: Int, name: String, desc: String): Boolean = true
|
||||
override fun shouldWriteField(access: Int, name: String, desc: String): Boolean = true
|
||||
override fun shouldWriteInnerClass(name: String, outerName: String?, innerName: String?): Boolean = !name.startsWith("helpers/")
|
||||
override val shouldTransformAnonymousTypes: Boolean get() = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +195,7 @@ class BytecodeListingTextCollectingVisitor(
|
||||
return null
|
||||
}
|
||||
|
||||
val returnType = Type.getReturnType(desc).className
|
||||
val returnType = transformAnonymousTypeIfNeeded(Type.getReturnType(desc)).className
|
||||
val parameterTypes = Type.getArgumentTypes(desc).map { it.className }
|
||||
val methodAnnotations = arrayListOf<String>()
|
||||
val parameterAnnotations = hashMapOf<Int, MutableList<String>>()
|
||||
@@ -235,7 +247,7 @@ class BytecodeListingTextCollectingVisitor(
|
||||
return null
|
||||
}
|
||||
|
||||
val type = Type.getType(desc).className
|
||||
val type = transformAnonymousTypeIfNeeded(Type.getType(desc)).className
|
||||
val fieldSignature = if (withSignatures) "<$signature> " else ""
|
||||
val fieldDeclaration = Declaration("field $fieldSignature$name: $type")
|
||||
declarationsInsideClass.add(fieldDeclaration)
|
||||
@@ -362,4 +374,20 @@ class BytecodeListingTextCollectingVisitor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformAnonymousTypeIfNeeded(type: Type): Type {
|
||||
if (filter.shouldTransformAnonymousTypes) {
|
||||
val node = allClasses[type]
|
||||
if (node != null && isAnonymousClass(node)) {
|
||||
return Type.getObjectType(node.interfaces.singleOrNull() ?: node.superName)
|
||||
}
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
private fun isAnonymousClass(node: ClassNode): Boolean {
|
||||
val innerClassAttr = node.innerClasses.find { it.name == node.name }
|
||||
return innerClassAttr != null && innerClassAttr.innerName == null && innerClassAttr.outerName == null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user