chore: update gradle and dependencies

This commit is contained in:
Skylot
2026-03-22 21:14:44 +00:00
parent 14a7b63707
commit 462e582bb8
34 changed files with 167 additions and 183 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ For Windows, you can download it from [oracle.com](https://www.oracle.com/java/t
You can use jadx in your java projects, check details on [wiki page](https://github.com/skylot/jadx/wiki/Use-jadx-as-a-library) You can use jadx in your java projects, check details on [wiki page](https://github.com/skylot/jadx/wiki/Use-jadx-as-a-library)
### Build from source ### Build from source
JDK 11 or higher must be installed: JDK 17 or higher must be installed:
``` ```
git clone https://github.com/skylot/jadx.git git clone https://github.com/skylot/jadx.git
cd jadx cd jadx
+4 -2
View File
@@ -8,7 +8,7 @@ import java.util.Locale
plugins { plugins {
id("com.github.ben-manes.versions") version "0.53.0" id("com.github.ben-manes.versions") version "0.53.0"
id("se.patrikerdes.use-latest-versions") version "0.2.19" id("se.patrikerdes.use-latest-versions") version "0.2.19"
id("com.diffplug.spotless") version "6.25.0" id("com.diffplug.spotless") version "8.4.0"
} }
val jadxVersion by extra { System.getenv("JADX_VERSION") ?: "dev" } val jadxVersion by extra { System.getenv("JADX_VERSION") ?: "dev" }
@@ -98,7 +98,9 @@ val copyArtifacts by tasks.registering(Copy::class) {
from(tasks.getByPath(":jadx-cli:installShadowDist")) { from(tasks.getByPath(":jadx-cli:installShadowDist")) {
exclude("**/*.jar") exclude("**/*.jar")
filter { line -> filter { line ->
jarCliPattern.matcher(line).replaceAll("jadx-$1-all.jar") jarCliPattern
.matcher(line)
.replaceAll("jadx-$1-all.jar")
.replace("-jar \"\\\"\$CLASSPATH\\\"\"", "-cp \"\\\"\$CLASSPATH\\\"\" jadx.cli.JadxCLI") .replace("-jar \"\\\"\$CLASSPATH\\\"\"", "-cp \"\\\"\$CLASSPATH\\\"\" jadx.cli.JadxCLI")
.replace("-jar \"%CLASSPATH%\"", "-cp \"%CLASSPATH%\" jadx.cli.JadxCLI") .replace("-jar \"%CLASSPATH%\"", "-cp \"%CLASSPATH%\" jadx.cli.JadxCLI")
} }
@@ -15,15 +15,15 @@ version = jadxVersion
dependencies { dependencies {
implementation("org.slf4j:slf4j-api:2.0.17") implementation("org.slf4j:slf4j-api:2.0.17")
compileOnly("org.jetbrains:annotations:26.0.2") compileOnly("org.jetbrains:annotations:26.1.0")
testImplementation("ch.qos.logback:logback-classic:1.5.22") testImplementation("ch.qos.logback:logback-classic:1.5.32")
testImplementation("org.assertj:assertj-core:3.27.6") testImplementation("org.assertj:assertj-core:3.27.7")
testImplementation("org.junit.jupiter:junit-jupiter:5.13.3") testImplementation("org.junit.jupiter:junit-jupiter:5.13.3")
testRuntimeOnly("org.junit.platform:junit-platform-launcher") testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testCompileOnly("org.jetbrains:annotations:26.0.2") testCompileOnly("org.jetbrains:annotations:26.1.0")
} }
repositories { repositories {
@@ -7,10 +7,10 @@ repositories {
} }
dependencies { dependencies {
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.24.0") rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.30.0")
rewrite("org.openrewrite.recipe:rewrite-logging-frameworks:3.20.0") rewrite("org.openrewrite.recipe:rewrite-logging-frameworks:3.26.0")
rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.24.0") rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.30.1")
rewrite("org.openrewrite.recipe:rewrite-static-analysis:2.24.0") rewrite("org.openrewrite.recipe:rewrite-static-analysis:2.30.1")
} }
tasks { tasks {
Binary file not shown.
+2 -2
View File
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -1
View File
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
+1 -1
View File
@@ -25,7 +25,7 @@ dependencies {
runtimeOnly(project(":jadx-plugins:jadx-apks-input")) runtimeOnly(project(":jadx-plugins:jadx-apks-input"))
implementation("org.jcommander:jcommander:2.0") implementation("org.jcommander:jcommander:2.0")
implementation("ch.qos.logback:logback-classic:1.5.22") implementation("ch.qos.logback:logback-classic:1.5.32")
implementation("com.google.code.gson:gson:2.13.2") implementation("com.google.code.gson:gson:2.13.2")
} }
+5 -2
View File
@@ -24,7 +24,7 @@ dependencies {
strictly("[3.33, 3.34[") // from 3.34 compiled with Java 17 strictly("[3.33, 3.34[") // from 3.34 compiled with Java 17
} }
} }
testImplementation("tools.profiler:async-profiler:4.2") testImplementation("tools.profiler:async-profiler:4.3")
} }
val jadxTestJavaVersion = getTestJavaVersion() val jadxTestJavaVersion = getTestJavaVersion()
@@ -32,7 +32,10 @@ val jadxTestJavaVersion = getTestJavaVersion()
fun getTestJavaVersion(): Int? { fun getTestJavaVersion(): Int? {
val envVarName = "JADX_TEST_JAVA_VERSION" val envVarName = "JADX_TEST_JAVA_VERSION"
val testJavaVer = System.getenv(envVarName)?.toInt() ?: return null val testJavaVer = System.getenv(envVarName)?.toInt() ?: return null
val currentJavaVer = java.toolchain.languageVersion.get().asInt() val currentJavaVer =
java.toolchain.languageVersion
.get()
.asInt()
if (testJavaVer < currentJavaVer) { if (testJavaVer < currentJavaVer) {
throw GradleException("'$envVarName' can't be set to lower version than $currentJavaVer") throw GradleException("'$envVarName' can't be set to lower version than $currentJavaVer")
} }
+21 -7
View File
@@ -55,7 +55,13 @@ dependencies {
implementation("com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0") implementation("com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0")
implementation("com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0") implementation("com.eclipsesource.j2v8:j2v8_win32_x86_64:4.6.0")
testImplementation(project.project(":jadx-core").sourceSets.getByName("test").output) testImplementation(
project
.project(":jadx-core")
.sourceSets
.getByName("test")
.output,
)
} }
val jadxVersion: String by rootProject.extra val jadxVersion: String by rootProject.extra
@@ -119,12 +125,14 @@ project.components.withType(AdhocComponentWithVariants::class.java).forEach { c
tasks.startShadowScripts { tasks.startShadowScripts {
doLast { doLast {
val newWindowsScriptContent = val newWindowsScriptContent =
windowsScript.readText() windowsScript
.readText()
.replace("java.exe", "javaw.exe") .replace("java.exe", "javaw.exe")
.replace("\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%", "start \"jadx-gui\" /B \"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%") .replace("\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%", "start \"jadx-gui\" /B \"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%")
// Add launch script path as a property // Add launch script path as a property
val newUnixScriptContent = val newUnixScriptContent =
unixScript.readText() unixScript
.readText()
.replace( .replace(
Regex("DEFAULT_JVM_OPTS=.+", RegexOption.MULTILINE), Regex("DEFAULT_JVM_OPTS=.+", RegexOption.MULTILINE),
{ result -> result.value + "\" \\\"-Djadx.launchScript.path=\$(realpath $0)\\\"\"" }, { result -> result.value + "\" \\\"-Djadx.launchScript.path=\$(realpath $0)\\\"\"" },
@@ -151,18 +159,24 @@ launch4j {
supportUrl.set("https://github.com/skylot/jadx") supportUrl.set("https://github.com/skylot/jadx")
bundledJrePath.set(if (project.hasProperty("bundleJRE")) "%EXEDIR%/jre" else "%JAVA_HOME%") bundledJrePath.set(if (project.hasProperty("bundleJRE")) "%EXEDIR%/jre" else "%JAVA_HOME%")
classpath.set(tasks.getByName("shadowJar").outputs.files.map { "%EXEDIR%/lib/${it.name}" }.sorted().toList()) classpath.set(
tasks
.getByName("shadowJar")
.outputs.files
.map { "%EXEDIR%/lib/${it.name}" }
.sorted()
.toList(),
)
println("Launch4J classpath: ${classpath.get()}") println("Launch4J classpath: ${classpath.get()}")
chdir.set("") // don't change current dir chdir.set("") // don't change current dir
libraryDir.set("") // don't add any libs libraryDir.set("") // don't add any libs
} }
fun escapeJVMOptions(): List<String> { fun escapeJVMOptions(): List<String> =
return application.applicationDefaultJvmArgs application.applicationDefaultJvmArgs
.toList() .toList()
.map { if (it.startsWith("-D")) "\"$it\"" else it } .map { if (it.startsWith("-D")) "\"$it\"" else it }
}
runtime { runtime {
addOptions("--strip-debug", "--no-header-files", "--no-man-pages") addOptions("--strip-debug", "--no-header-files", "--no-man-pages")
@@ -32,18 +32,14 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
} }
} }
override fun isActionEnabled(node: JNode?): Boolean { override fun isActionEnabled(node: JNode?): Boolean = node is JMethod || node is JClass || node is JField
return node is JMethod || node is JClass || node is JField
}
private fun generateXposedSnippet(node: JNode): String { private fun generateXposedSnippet(node: JNode): String = when (node) {
return when (node) {
is JMethod -> generateMethodSnippet(node) is JMethod -> generateMethodSnippet(node)
is JClass -> generateClassSnippet(node) is JClass -> generateClassSnippet(node)
is JField -> generateFieldSnippet(node) is JField -> generateFieldSnippet(node)
else -> throw JadxRuntimeException("Unsupported node type: " + node.javaClass) else -> throw JadxRuntimeException("Unsupported node type: " + node.javaClass)
} }
}
private fun generateMethodSnippet(jMethod: JMethod): String { private fun generateMethodSnippet(jMethod: JMethod): String {
val javaMethod = jMethod.javaMethod val javaMethod = jMethod.javaMethod
@@ -73,6 +69,7 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
super.afterHookedMethod(param); super.afterHookedMethod(param);
} }
});""" });"""
XposedCodegenLanguage.KOTLIN -> XposedCodegenLanguage.KOTLIN ->
"""XposedHelpers.%s("%s", classLoader, %s, object : XC_MethodHook() { """XposedHelpers.%s("%s", classLoader, %s, object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) { override fun beforeHookedMethod(param: MethodHookParam) {
@@ -88,12 +85,14 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
return String.format(template, xposedMethod, rawClassName, args.joinToString(", ")) return String.format(template, xposedMethod, rawClassName, args.joinToString(", "))
} }
private fun fixTypeContent(type: ArgType): String { private fun fixTypeContent(type: ArgType): String = when {
return when {
type.isGeneric -> "\"${type.`object`}\"" type.isGeneric -> "\"${type.`object`}\""
type.isGenericType && type.isObject && type.isTypeKnown -> "java.lang.Object" type.isGenericType && type.isObject && type.isTypeKnown -> "java.lang.Object"
type.isPrimitive -> when (language) { type.isPrimitive -> when (language) {
XposedCodegenLanguage.JAVA -> "$type.class" XposedCodegenLanguage.JAVA -> "$type.class"
XposedCodegenLanguage.KOTLIN -> when (type.primitiveType) { XposedCodegenLanguage.KOTLIN -> when (type.primitiveType) {
PrimitiveType.BOOLEAN -> "Boolean::class.javaPrimitiveType" PrimitiveType.BOOLEAN -> "Boolean::class.javaPrimitiveType"
PrimitiveType.CHAR -> "Char::class.javaPrimitiveType" PrimitiveType.CHAR -> "Char::class.javaPrimitiveType"
@@ -109,9 +108,9 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
else -> throw JadxRuntimeException("Unknown or null primitive type: $type") else -> throw JadxRuntimeException("Unknown or null primitive type: $type")
} }
} }
else -> "\"$type\"" else -> "\"$type\""
} }
}
private fun generateClassSnippet(jClass: JClass): String { private fun generateClassSnippet(jClass: JClass): String {
val javaClass = jClass.cls val javaClass = jClass.cls
+1 -1
View File
@@ -11,5 +11,5 @@ dependencies {
implementation("com.google.code.gson:gson:2.13.2") implementation("com.google.code.gson:gson:2.13.2")
implementation("commons-io:commons-io:2.21.0") implementation("commons-io:commons-io:2.21.0")
testImplementation("com.squareup.okhttp3:mockwebserver3:5.3.0") testImplementation("com.squareup.okhttp3:mockwebserver3:5.3.2")
} }
+1 -1
View File
@@ -5,7 +5,7 @@ plugins {
dependencies { dependencies {
compileOnly(project(":jadx-core")) compileOnly(project(":jadx-core"))
implementation("com.android.tools.build:aapt2-proto:8.13.2-14304508") implementation("com.android.tools.build:aapt2-proto:9.1.0-14792394")
implementation("com.google.protobuf:protobuf-java") { implementation("com.google.protobuf:protobuf-java") {
version { version {
require("3.25.3") // version 4 conflict with `aapt2-proto` require("3.25.3") // version 4 conflict with `aapt2-proto`
@@ -21,7 +21,5 @@ object ApkmUtils {
} }
} }
fun isSupported(manifest: ApkmManifest): Boolean { fun isSupported(manifest: ApkmManifest): Boolean = manifest.apkmVersion != -1
return manifest.apkmVersion != -1
}
} }
@@ -7,7 +7,7 @@ dependencies {
implementation(project(":jadx-plugins:jadx-dex-input")) implementation(project(":jadx-plugins:jadx-dex-input"))
implementation("com.jakewharton.android.repackaged:dalvik-dx:16.0.1") implementation("com.jakewharton.android.repackaged:dalvik-dx:16.0.1")
implementation("com.android.tools:r8:8.13.17") implementation("com.android.tools:r8:9.1.31")
implementation("org.ow2.asm:asm:9.9.1") implementation("org.ow2.asm:asm:9.9.1")
} }
@@ -24,6 +24,9 @@ public class D8Converter {
.setMinApiLevel(30) .setMinApiLevel(30)
.setIntermediate(true) .setIntermediate(true)
.setDisableDesugaring(!options.isD8Desugar()) .setDisableDesugaring(!options.isD8Desugar())
.setEnableVerboseSyntheticNames(true)
.setOptimizeMultidexForLinearAlloc(false)
.setIncludeClassesChecksum(false)
.build(); .build();
D8.run(d8Command); D8.run(d8Command);
} }
@@ -8,7 +8,13 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.10") implementation("org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.10")
testImplementation(project.project(":jadx-core").sourceSets.getByName("test").output) testImplementation(
project
.project(":jadx-core")
.sourceSets
.getByName("test")
.output,
)
testImplementation("org.apache.commons:commons-lang3:3.20.0") testImplementation("org.apache.commons:commons-lang3:3.20.0")
testRuntimeOnly(project(":jadx-plugins:jadx-smali-input")) testRuntimeOnly(project(":jadx-plugins:jadx-smali-input"))
@@ -56,13 +56,9 @@ class KotlinMetadataOptions : BasePluginOptionsBuilder() {
.setter { isGetters = it } .setter { isGetters = it }
} }
fun isPreparePassNeeded(): Boolean { fun isPreparePassNeeded(): Boolean = isClassAlias
return isClassAlias
}
fun isDecompilePassNeeded(): Boolean { fun isDecompilePassNeeded(): Boolean = isMethodArgs || isFields || isCompanion || isDataClass || isToString || isGetters
return isMethodArgs || isFields || isCompanion || isDataClass || isToString || isGetters
}
companion object { companion object {
const val CLASS_ALIAS_OPT = "$PLUGIN_ID.class-alias" const val CLASS_ALIAS_OPT = "$PLUGIN_ID.class-alias"
@@ -10,9 +10,7 @@ class KotlinMetadataPlugin : JadxPlugin {
private val options = KotlinMetadataOptions() private val options = KotlinMetadataOptions()
override fun getPluginInfo(): JadxPluginInfo { override fun getPluginInfo(): JadxPluginInfo = JadxPluginInfo(PLUGIN_ID, "Kotlin Metadata", "Use kotlin.Metadata annotation for code generation")
return JadxPluginInfo(PLUGIN_ID, "Kotlin Metadata", "Use kotlin.Metadata annotation for code generation")
}
override fun init(context: JadxPluginContext) { override fun init(context: JadxPluginContext) {
context.registerOptions(options) context.registerOptions(options)
@@ -18,13 +18,11 @@ class KotlinMetadataDecompilePass(
private val options: KotlinMetadataOptions, private val options: KotlinMetadataOptions,
) : JadxDecompilePass { ) : JadxDecompilePass {
override fun getInfo(): JadxPassInfo { override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
return OrderedJadxPassInfo(
"KotlinMetadataDecompile", "KotlinMetadataDecompile",
"Use kotlin.Metadata annotation perform various renames", "Use kotlin.Metadata annotation perform various renames",
) )
.before("CodeRenameVisitor") .before("CodeRenameVisitor")
}
override fun init(root: RootNode) { override fun init(root: RootNode) {
} }
@@ -12,13 +12,11 @@ class KotlinMetadataPreparePass(
private val options: KotlinMetadataOptions, private val options: KotlinMetadataOptions,
) : JadxPreparePass { ) : JadxPreparePass {
override fun getInfo(): JadxPassInfo { override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
return OrderedJadxPassInfo(
"KotlinMetadataPrepare", "KotlinMetadataPrepare",
"Use kotlin.Metadata annotation to rename class & package", "Use kotlin.Metadata annotation to rename class & package",
) )
.before("RenameVisitor") .before("RenameVisitor")
}
override fun init(root: RootNode) { override fun init(root: RootNode) {
if (options.isClassAlias) { if (options.isClassAlias) {
@@ -11,25 +11,19 @@ class KmClassWrapper private constructor(
private val kmCls: KmClass, private val kmCls: KmClass,
) { ) {
fun getMethodArgs() = fun getMethodArgs() = KotlinMetadataUtils.mapMethodArgs(cls, kmCls)
KotlinMetadataUtils.mapMethodArgs(cls, kmCls)
fun getFields() = fun getFields() = KotlinMetadataUtils.mapFields(cls, kmCls)
KotlinMetadataUtils.mapFields(cls, kmCls)
fun getCompanion() = fun getCompanion() = KotlinMetadataUtils.mapCompanion(cls, kmCls)
KotlinMetadataUtils.mapCompanion(cls, kmCls)
fun isDataClass() = fun isDataClass() = kmCls.isData
kmCls.isData
// does not require metadata, may be useful for plain java ? // does not require metadata, may be useful for plain java ?
fun parseToString() = fun parseToString() = KotlinUtils.parseToString(cls)
KotlinUtils.parseToString(cls)
// does not require metadata, may be useful for plain java ? // does not require metadata, may be useful for plain java ?
fun getGetters() = fun getGetters() = KotlinUtils.findGetters(cls)
KotlinUtils.findGetters(cls)
companion object { companion object {
@@ -48,12 +48,10 @@ private fun IAnnotation.getParamAsStringArray(paramName: String): Array<String>?
?.toTypedArray() ?.toTypedArray()
} }
private fun IAnnotation.getParamAsIntArray(paramName: String): IntArray? { private fun IAnnotation.getParamAsIntArray(paramName: String): IntArray? = getParamsAsList(paramName)
return getParamsAsList(paramName)
?.map<EncodedValue, Any?>(EncodedValue::getValue) ?.map<EncodedValue, Any?>(EncodedValue::getValue)
?.map { it as Int } ?.map { it as Int }
?.toIntArray() ?.toIntArray()
}
private fun IAnnotation.getParamAsInt(paramName: String): Int? { private fun IAnnotation.getParamAsInt(paramName: String): Int? {
val encodedValue = values[paramName] val encodedValue = values[paramName]
@@ -67,6 +65,4 @@ private fun IAnnotation.getParamAsString(paramName: String): String? {
return encodedValue?.value?.let { it as String } return encodedValue?.value?.let { it as String }
} }
fun ClassNode.getKotlinClassMetadata(): KotlinClassMetadata? { fun ClassNode.getKotlinClassMetadata(): KotlinClassMetadata? = getMetadata()?.let(KotlinClassMetadata::readLenient)
return getMetadata()?.let(KotlinClassMetadata::readLenient)
}
@@ -33,15 +33,13 @@ object KotlinUtils {
} }
} }
private fun getFieldGetterMethod(cls: ClassNode, field: FieldInfo): MethodNode? { private fun getFieldGetterMethod(cls: ClassNode, field: FieldInfo): MethodNode? = cls.methods.firstOrNull {
return cls.methods.firstOrNull {
it.returnType == field.type && it.returnType == field.type &&
it.argTypes.isEmpty() && it.argTypes.isEmpty() &&
it.insnsCount == 3 && it.insnsCount == 3 &&
it.sVars.size == 2 && it.sVars.size == 2 &&
(it.sVars[1].assignInsn as? IndexInsnNode)?.index == field (it.sVars[1].assignInsn as? IndexInsnNode)?.index == field
} }
}
private fun getGetterAlias(fieldAlias: String): String { private fun getGetterAlias(fieldAlias: String): String {
val capitalized = fieldAlias.replaceFirstChar { val capitalized = fieldAlias.replaceFirstChar {
@@ -84,7 +82,5 @@ object KotlinUtils {
} }
} }
private fun getDefaultMethodAlias(alias: String): String { private fun getDefaultMethodAlias(alias: String): String = "$alias\$default"
return "$alias\$default"
}
} }
@@ -5,6 +5,5 @@ import org.slf4j.LoggerFactory
inline val <reified T : Any> T.LOG: Logger get() = LoggerFactory.getLogger(T::class.java) inline val <reified T : Any> T.LOG: Logger get() = LoggerFactory.getLogger(T::class.java)
inline fun <reified T : Any, R> T.runCatchingLog(msg: String? = null, block: () -> R) = inline fun <reified T : Any, R> T.runCatchingLog(msg: String? = null, block: () -> R) = runCatching(block)
runCatching(block)
.onFailure { LOG.error(msg.orEmpty(), it) } .onFailure { LOG.error(msg.orEmpty(), it) }
@@ -124,23 +124,17 @@ class ToStringParser private constructor(mthToString: MethodNode) {
) )
} }
private fun isStartStringBuilder(inst: InsnNode): Boolean { private fun isStartStringBuilder(inst: InsnNode): Boolean = inst is ConstructorInsn &&
return inst is ConstructorInsn &&
inst.isNewInstance && inst.isNewInstance &&
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER
}
private fun isAppendInvoke(inst: InsnNode): Boolean { private fun isAppendInvoke(inst: InsnNode): Boolean = inst is InvokeNode &&
return inst is InvokeNode &&
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER && inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
inst.callMth.name == "append" && inst.callMth.name == "append" &&
inst.argsCount == 2 inst.argsCount == 2
}
private fun isToString(inst: InsnNode): Boolean { private fun isToString(inst: InsnNode): Boolean = inst is InvokeNode &&
return inst is InvokeNode &&
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER && inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
inst.callMth.shortId == Consts.MTH_TOSTRING_SIGNATURE inst.callMth.shortId == Consts.MTH_TOSTRING_SIGNATURE
} }
} }
}
@@ -159,7 +159,6 @@ class TestKotlinMetadata : SmaliTest() {
} }
} }
private fun assertThatClass(): JadxCodeAssertions = private fun assertThatClass(): JadxCodeAssertions = assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinMetadata", "a"))
assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinMetadata", "a"))
.code() .code()
} }
@@ -6,7 +6,13 @@ plugins {
dependencies { dependencies {
api(project(":jadx-core")) api(project(":jadx-core"))
testImplementation(project.project(":jadx-core").sourceSets.getByName("test").output) testImplementation(
project
.project(":jadx-core")
.sourceSets
.getByName("test")
.output,
)
testImplementation("org.apache.commons:commons-lang3:3.20.0") testImplementation("org.apache.commons:commons-lang3:3.20.0")
testRuntimeOnly(project(":jadx-plugins:jadx-smali-input")) testRuntimeOnly(project(":jadx-plugins:jadx-smali-input"))
@@ -14,9 +14,7 @@ class KotlinSmapOptions : BasePluginOptionsBuilder() {
.setter { isClassAliasSourceDbg = it } .setter { isClassAliasSourceDbg = it }
} }
fun isClassSourceDbg(): Boolean { fun isClassSourceDbg(): Boolean = isClassAliasSourceDbg
return isClassAliasSourceDbg
}
companion object { companion object {
const val CLASS_ALIAS_SOURCE_DBG_OPT = "$PLUGIN_ID.class-alias-source-dbg" const val CLASS_ALIAS_SOURCE_DBG_OPT = "$PLUGIN_ID.class-alias-source-dbg"
@@ -9,9 +9,7 @@ class KotlinSmapPlugin : JadxPlugin {
private val options = KotlinSmapOptions() private val options = KotlinSmapOptions()
override fun getPluginInfo(): JadxPluginInfo { override fun getPluginInfo(): JadxPluginInfo = JadxPluginInfo(PLUGIN_ID, "Kotlin SMAP", "Use kotlin.SourceDebugExtension annotation for rename class alias")
return JadxPluginInfo(PLUGIN_ID, "Kotlin SMAP", "Use kotlin.SourceDebugExtension annotation for rename class alias")
}
override fun init(context: JadxPluginContext) { override fun init(context: JadxPluginContext) {
context.registerOptions(options) context.registerOptions(options)
@@ -33,8 +33,7 @@ class SMAP(val fileMappings: List<FileMapping>) {
class FileMapping(val name: String, val path: String) { class FileMapping(val name: String, val path: String) {
val lineMappings = arrayListOf<RangeMapping>() val lineMappings = arrayListOf<RangeMapping>()
fun toSourceInfo(): SourceInfo = fun toSourceInfo(): SourceInfo = SourceInfo(
SourceInfo(
name, name,
path, path,
lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) }, lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) },
@@ -51,25 +50,19 @@ class FileMapping(val name: String, val path: String) {
return mapping.mapSourceToDest(source) return mapping.mapSourceToDest(source)
} }
private fun RangeMapping.canReuseFor(newSource: Int, globalMaxDest: Int, newCallSite: SourcePosition?): Boolean = private fun RangeMapping.canReuseFor(newSource: Int, globalMaxDest: Int, newCallSite: SourcePosition?): Boolean = callSite == newCallSite && (newSource - source) in 0 until range + (if (globalMaxDest in this) 10 else 0)
callSite == newCallSite && (newSource - source) in 0 until range + (if (globalMaxDest in this) 10 else 0)
fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping = fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping = RangeMapping(source, dest, range, callSite, parent = this).also { lineMappings.add(it) }
RangeMapping(source, dest, range, callSite, parent = this).also { lineMappings.add(it) }
} }
data class RangeMapping(val source: Int, val dest: Int, var range: Int, val callSite: SourcePosition?, val parent: FileMapping) { data class RangeMapping(val source: Int, val dest: Int, var range: Int, val callSite: SourcePosition?, val parent: FileMapping) {
operator fun contains(destLine: Int): Boolean = operator fun contains(destLine: Int): Boolean = dest <= destLine && destLine < dest + range
dest <= destLine && destLine < dest + range
fun hasMappingForSource(sourceLine: Int): Boolean = fun hasMappingForSource(sourceLine: Int): Boolean = source <= sourceLine && sourceLine < source + range
source <= sourceLine && sourceLine < source + range
fun mapDestToSource(destLine: Int): SourcePosition = fun mapDestToSource(destLine: Int): SourcePosition = SourcePosition(source + (destLine - dest), parent.name, parent.path)
SourcePosition(source + (destLine - dest), parent.name, parent.path)
fun mapSourceToDest(sourceLine: Int): Int = fun mapSourceToDest(sourceLine: Int): Int = dest + (sourceLine - source)
dest + (sourceLine - source)
} }
val RangeMapping.toRange: IntRange val RangeMapping.toRange: IntRange
@@ -12,13 +12,11 @@ class KotlinSourceDebugExtensionPass(
private val options: KotlinSmapOptions, private val options: KotlinSmapOptions,
) : JadxPreparePass { ) : JadxPreparePass {
override fun getInfo(): JadxPassInfo { override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
return OrderedJadxPassInfo(
"SourceDebugExtensionPrepare", "SourceDebugExtensionPrepare",
"Use kotlin.jvm.internal.SourceDebugExtension annotation to rename class & package", "Use kotlin.jvm.internal.SourceDebugExtension annotation to rename class & package",
) )
.before("RenameVisitor") .before("RenameVisitor")
}
override fun init(root: RootNode) { override fun init(root: RootNode) {
if (options.isClassAliasSourceDbg) { if (options.isClassAliasSourceDbg) {
@@ -22,8 +22,7 @@ import jadx.plugins.kotlin.smap.model.KOTLIN_STRATA_NAME
import jadx.plugins.kotlin.smap.model.SMAP import jadx.plugins.kotlin.smap.model.SMAP
object SMAPParser { object SMAPParser {
fun parseOrNull(mappingInfo: String): SMAP? = fun parseOrNull(mappingInfo: String): SMAP? = if (mappingInfo.isNotEmpty()) {
if (mappingInfo.isNotEmpty()) {
parseStratum(mappingInfo, KOTLIN_STRATA_NAME, parseStratum(mappingInfo, KOTLIN_DEBUG_STRATA_NAME, null)) parseStratum(mappingInfo, KOTLIN_STRATA_NAME, parseStratum(mappingInfo, KOTLIN_DEBUG_STRATA_NAME, null))
} else { } else {
null null
@@ -55,9 +54,7 @@ object SMAPParser {
pos++ pos++
} }
override fun hasNext(): Boolean { override fun hasNext(): Boolean = currentLine != null
return currentLine != null
}
override fun next(): String { override fun next(): String {
val res = currentLine ?: throw NoSuchElementException() val res = currentLine ?: throw NoSuchElementException()
@@ -105,7 +102,9 @@ object SMAPParser {
val range = when { val range = when {
// These two fields have a different meaning, but for compatibility we treat them the same. See `SMAPBuilder`. // These two fields have a different meaning, but for compatibility we treat them the same. See `SMAPBuilder`.
destMultiplierSeparator != line.length -> line.substring(destMultiplierSeparator + 1).toInt() destMultiplierSeparator != line.length -> line.substring(destMultiplierSeparator + 1).toInt()
sourceRangeSeparator != destSeparator -> line.substring(sourceRangeSeparator + 1, destSeparator).toInt() sourceRangeSeparator != destSeparator -> line.substring(sourceRangeSeparator + 1, destSeparator).toInt()
else -> 1 else -> 1
} }
// Here we assume that each range in `Kotlin` is entirely within at most one range in `KotlinDebug`. // Here we assume that each range in `Kotlin` is entirely within at most one range in `KotlinDebug`.
@@ -28,7 +28,6 @@ class TestSourceDebugExtension : SmaliTest() {
} }
} }
private fun assertThatClass(): JadxCodeAssertions = private fun assertThatClass(): JadxCodeAssertions = assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinSourceDebugExtension", "C6"))
assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinSourceDebugExtension", "C6"))
.code() .code()
} }