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

main.jadx.plugins.kotlin.metadata.utils.KotlinUtils.kt Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
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