main.jadx.plugins.kotlin.metadata.utils.KotlinUtils.kt Maven / Gradle / Ivy
package jadx.plugins.kotlin.metadata.utils
import jadx.core.Consts
import jadx.core.dex.info.FieldInfo
import jadx.core.dex.instructions.IndexInsnNode
import jadx.core.dex.instructions.InsnType
import jadx.core.dex.instructions.InvokeNode
import jadx.core.dex.instructions.args.PrimitiveType
import jadx.core.dex.nodes.ClassNode
import jadx.core.dex.nodes.FieldNode
import jadx.core.dex.nodes.MethodNode
import jadx.plugins.kotlin.metadata.model.MethodRename
import jadx.plugins.kotlin.metadata.model.ToStringRename
import java.util.Locale
object KotlinUtils {
fun parseToString(cls: ClassNode): ToStringRename? {
val mthToString = cls.searchMethodByShortId(Consts.MTH_TOSTRING_SIGNATURE)
?: return null
return ToStringParser.parse(mthToString)
}
fun findGetters(cls: ClassNode): List {
return cls.fields.filter(FieldNode::isInstance).mapNotNull { field ->
val mth = getFieldGetterMethod(cls, field.fieldInfo)
?: return@mapNotNull null
MethodRename(
mth = mth,
alias = getGetterAlias(field.alias),
)
}
}
private fun getFieldGetterMethod(cls: ClassNode, field: FieldInfo): MethodNode? {
return cls.methods.firstOrNull {
it.returnType == field.type &&
it.argTypes.isEmpty() &&
it.insnsCount == 3 &&
it.sVars.size == 2 &&
(it.sVars[1].assignInsn as? IndexInsnNode)?.index == field
}
}
private fun getGetterAlias(fieldAlias: String): String {
val capitalized = fieldAlias.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString()
}
return "get$capitalized"
}
// untested & overly complicated
fun parseDefaultMethods(cls: ClassNode): List {
val possibleMthList = cls.methods.filter {
it.accessFlags.isStatic && it.accessFlags.isSynthetic &&
it.argTypes.run {
size > 3 &&
first().isObject && first().`object` == cls.fullName &&
get(size - 2).isPrimitive && get(size - 2).primitiveType == PrimitiveType.INT &&
last().isObject && last().`object` == Consts.CLASS_OBJECT
}
}
val insnList = possibleMthList.filter {
it.exitBlock.run {
iDom != null && iDom.instructions.firstOrNull()?.type == InsnType.RETURN
iDom.iDom != null
} &&
it.exitBlock.iDom.iDom.run {
instructions.firstOrNull() is InvokeNode
}
}
val remapped = insnList.mapNotNull {
val insn = it.exitBlock.iDom.iDom.instructions.first() as InvokeNode
cls.searchMethodByShortId(insn.callMth.shortId)?.run { it to this }
}
return remapped.map { (defaultMethod, originalMethod) ->
MethodRename(
mth = defaultMethod,
alias = getDefaultMethodAlias(originalMethod.alias),
)
}
}
private fun getDefaultMethodAlias(alias: String): String {
return "$alias\$default"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy