chore: update gradle and dependencies
This commit is contained in:
@@ -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)
|
||||
|
||||
### 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
|
||||
cd jadx
|
||||
|
||||
+4
-2
@@ -8,7 +8,7 @@ import java.util.Locale
|
||||
plugins {
|
||||
id("com.github.ben-manes.versions") version "0.53.0"
|
||||
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" }
|
||||
@@ -98,7 +98,9 @@ val copyArtifacts by tasks.registering(Copy::class) {
|
||||
from(tasks.getByPath(":jadx-cli:installShadowDist")) {
|
||||
exclude("**/*.jar")
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -15,15 +15,15 @@ version = jadxVersion
|
||||
|
||||
dependencies {
|
||||
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("org.assertj:assertj-core:3.27.6")
|
||||
testImplementation("ch.qos.logback:logback-classic:1.5.32")
|
||||
testImplementation("org.assertj:assertj-core:3.27.7")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.13.3")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
testCompileOnly("org.jetbrains:annotations:26.0.2")
|
||||
testCompileOnly("org.jetbrains:annotations:26.1.0")
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -7,10 +7,10 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.24.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-logging-frameworks:3.20.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.24.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-static-analysis:2.24.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.30.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-logging-frameworks:3.26.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-migrate-java:3.30.1")
|
||||
rewrite("org.openrewrite.recipe:rewrite-static-analysis:2.30.1")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (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.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
||||
@@ -25,7 +25,7 @@ dependencies {
|
||||
runtimeOnly(project(":jadx-plugins:jadx-apks-input"))
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ dependencies {
|
||||
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()
|
||||
@@ -32,7 +32,10 @@ val jadxTestJavaVersion = getTestJavaVersion()
|
||||
fun getTestJavaVersion(): Int? {
|
||||
val envVarName = "JADX_TEST_JAVA_VERSION"
|
||||
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) {
|
||||
throw GradleException("'$envVarName' can't be set to lower version than $currentJavaVer")
|
||||
}
|
||||
|
||||
@@ -55,7 +55,13 @@ dependencies {
|
||||
implementation("com.eclipsesource.j2v8:j2v8_linux_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
|
||||
@@ -119,12 +125,14 @@ project.components.withType(AdhocComponentWithVariants::class.java).forEach { c
|
||||
tasks.startShadowScripts {
|
||||
doLast {
|
||||
val newWindowsScriptContent =
|
||||
windowsScript.readText()
|
||||
windowsScript
|
||||
.readText()
|
||||
.replace("java.exe", "javaw.exe")
|
||||
.replace("\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%", "start \"jadx-gui\" /B \"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%")
|
||||
// Add launch script path as a property
|
||||
val newUnixScriptContent =
|
||||
unixScript.readText()
|
||||
unixScript
|
||||
.readText()
|
||||
.replace(
|
||||
Regex("DEFAULT_JVM_OPTS=.+", RegexOption.MULTILINE),
|
||||
{ result -> result.value + "\" \\\"-Djadx.launchScript.path=\$(realpath $0)\\\"\"" },
|
||||
@@ -151,18 +159,24 @@ launch4j {
|
||||
supportUrl.set("https://github.com/skylot/jadx")
|
||||
|
||||
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()}")
|
||||
|
||||
chdir.set("") // don't change current dir
|
||||
libraryDir.set("") // don't add any libs
|
||||
}
|
||||
|
||||
fun escapeJVMOptions(): List<String> {
|
||||
return application.applicationDefaultJvmArgs
|
||||
fun escapeJVMOptions(): List<String> =
|
||||
application.applicationDefaultJvmArgs
|
||||
.toList()
|
||||
.map { if (it.startsWith("-D")) "\"$it\"" else it }
|
||||
}
|
||||
|
||||
runtime {
|
||||
addOptions("--strip-debug", "--no-header-files", "--no-man-pages")
|
||||
|
||||
@@ -32,17 +32,13 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
|
||||
}
|
||||
}
|
||||
|
||||
override fun isActionEnabled(node: JNode?): Boolean {
|
||||
return node is JMethod || node is JClass || node is JField
|
||||
}
|
||||
override fun isActionEnabled(node: JNode?): Boolean = node is JMethod || node is JClass || node is JField
|
||||
|
||||
private fun generateXposedSnippet(node: JNode): String {
|
||||
return when (node) {
|
||||
is JMethod -> generateMethodSnippet(node)
|
||||
is JClass -> generateClassSnippet(node)
|
||||
is JField -> generateFieldSnippet(node)
|
||||
else -> throw JadxRuntimeException("Unsupported node type: " + node.javaClass)
|
||||
}
|
||||
private fun generateXposedSnippet(node: JNode): String = when (node) {
|
||||
is JMethod -> generateMethodSnippet(node)
|
||||
is JClass -> generateClassSnippet(node)
|
||||
is JField -> generateFieldSnippet(node)
|
||||
else -> throw JadxRuntimeException("Unsupported node type: " + node.javaClass)
|
||||
}
|
||||
|
||||
private fun generateMethodSnippet(jMethod: JMethod): String {
|
||||
@@ -73,6 +69,7 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
|
||||
super.afterHookedMethod(param);
|
||||
}
|
||||
});"""
|
||||
|
||||
XposedCodegenLanguage.KOTLIN ->
|
||||
"""XposedHelpers.%s("%s", classLoader, %s, object : XC_MethodHook() {
|
||||
override fun beforeHookedMethod(param: MethodHookParam) {
|
||||
@@ -88,29 +85,31 @@ class XposedAction(codeArea: CodeArea) : JNodeAction(ActionModel.XPOSED_COPY, co
|
||||
return String.format(template, xposedMethod, rawClassName, args.joinToString(", "))
|
||||
}
|
||||
|
||||
private fun fixTypeContent(type: ArgType): String {
|
||||
return when {
|
||||
type.isGeneric -> "\"${type.`object`}\""
|
||||
type.isGenericType && type.isObject && type.isTypeKnown -> "java.lang.Object"
|
||||
type.isPrimitive -> when (language) {
|
||||
XposedCodegenLanguage.JAVA -> "$type.class"
|
||||
XposedCodegenLanguage.KOTLIN -> when (type.primitiveType) {
|
||||
PrimitiveType.BOOLEAN -> "Boolean::class.javaPrimitiveType"
|
||||
PrimitiveType.CHAR -> "Char::class.javaPrimitiveType"
|
||||
PrimitiveType.BYTE -> "Byte::class.javaPrimitiveType"
|
||||
PrimitiveType.SHORT -> "Short::class.javaPrimitiveType"
|
||||
PrimitiveType.INT -> "Int::class.javaPrimitiveType"
|
||||
PrimitiveType.FLOAT -> "Float::class.javaPrimitiveType"
|
||||
PrimitiveType.LONG -> "Long::class.javaPrimitiveType"
|
||||
PrimitiveType.DOUBLE -> "Double::class.javaPrimitiveType"
|
||||
PrimitiveType.OBJECT -> "Any::class.java"
|
||||
PrimitiveType.ARRAY -> "Array::class.java"
|
||||
PrimitiveType.VOID -> "Void::class.javaPrimitiveType"
|
||||
else -> throw JadxRuntimeException("Unknown or null primitive type: $type")
|
||||
}
|
||||
private fun fixTypeContent(type: ArgType): String = when {
|
||||
type.isGeneric -> "\"${type.`object`}\""
|
||||
|
||||
type.isGenericType && type.isObject && type.isTypeKnown -> "java.lang.Object"
|
||||
|
||||
type.isPrimitive -> when (language) {
|
||||
XposedCodegenLanguage.JAVA -> "$type.class"
|
||||
|
||||
XposedCodegenLanguage.KOTLIN -> when (type.primitiveType) {
|
||||
PrimitiveType.BOOLEAN -> "Boolean::class.javaPrimitiveType"
|
||||
PrimitiveType.CHAR -> "Char::class.javaPrimitiveType"
|
||||
PrimitiveType.BYTE -> "Byte::class.javaPrimitiveType"
|
||||
PrimitiveType.SHORT -> "Short::class.javaPrimitiveType"
|
||||
PrimitiveType.INT -> "Int::class.javaPrimitiveType"
|
||||
PrimitiveType.FLOAT -> "Float::class.javaPrimitiveType"
|
||||
PrimitiveType.LONG -> "Long::class.javaPrimitiveType"
|
||||
PrimitiveType.DOUBLE -> "Double::class.javaPrimitiveType"
|
||||
PrimitiveType.OBJECT -> "Any::class.java"
|
||||
PrimitiveType.ARRAY -> "Array::class.java"
|
||||
PrimitiveType.VOID -> "Void::class.javaPrimitiveType"
|
||||
else -> throw JadxRuntimeException("Unknown or null primitive type: $type")
|
||||
}
|
||||
else -> "\"$type\""
|
||||
}
|
||||
|
||||
else -> "\"$type\""
|
||||
}
|
||||
|
||||
private fun generateClassSnippet(jClass: JClass): String {
|
||||
|
||||
@@ -11,5 +11,5 @@ dependencies {
|
||||
implementation("com.google.code.gson:gson:2.13.2")
|
||||
implementation("commons-io:commons-io:2.21.0")
|
||||
|
||||
testImplementation("com.squareup.okhttp3:mockwebserver3:5.3.0")
|
||||
testImplementation("com.squareup.okhttp3:mockwebserver3:5.3.2")
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ plugins {
|
||||
dependencies {
|
||||
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") {
|
||||
version {
|
||||
require("3.25.3") // version 4 conflict with `aapt2-proto`
|
||||
|
||||
@@ -21,7 +21,5 @@ object ApkmUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun isSupported(manifest: ApkmManifest): Boolean {
|
||||
return manifest.apkmVersion != -1
|
||||
}
|
||||
fun isSupported(manifest: ApkmManifest): Boolean = manifest.apkmVersion != -1
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ dependencies {
|
||||
|
||||
implementation(project(":jadx-plugins:jadx-dex-input"))
|
||||
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")
|
||||
}
|
||||
|
||||
+3
@@ -24,6 +24,9 @@ public class D8Converter {
|
||||
.setMinApiLevel(30)
|
||||
.setIntermediate(true)
|
||||
.setDisableDesugaring(!options.isD8Desugar())
|
||||
.setEnableVerboseSyntheticNames(true)
|
||||
.setOptimizeMultidexForLinearAlloc(false)
|
||||
.setIncludeClassesChecksum(false)
|
||||
.build();
|
||||
D8.run(d8Command);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,13 @@ dependencies {
|
||||
|
||||
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")
|
||||
|
||||
testRuntimeOnly(project(":jadx-plugins:jadx-smali-input"))
|
||||
|
||||
+2
-6
@@ -56,13 +56,9 @@ class KotlinMetadataOptions : BasePluginOptionsBuilder() {
|
||||
.setter { isGetters = it }
|
||||
}
|
||||
|
||||
fun isPreparePassNeeded(): Boolean {
|
||||
return isClassAlias
|
||||
}
|
||||
fun isPreparePassNeeded(): Boolean = isClassAlias
|
||||
|
||||
fun isDecompilePassNeeded(): Boolean {
|
||||
return isMethodArgs || isFields || isCompanion || isDataClass || isToString || isGetters
|
||||
}
|
||||
fun isDecompilePassNeeded(): Boolean = isMethodArgs || isFields || isCompanion || isDataClass || isToString || isGetters
|
||||
|
||||
companion object {
|
||||
const val CLASS_ALIAS_OPT = "$PLUGIN_ID.class-alias"
|
||||
|
||||
+1
-3
@@ -10,9 +10,7 @@ class KotlinMetadataPlugin : JadxPlugin {
|
||||
|
||||
private val options = KotlinMetadataOptions()
|
||||
|
||||
override fun getPluginInfo(): JadxPluginInfo {
|
||||
return JadxPluginInfo(PLUGIN_ID, "Kotlin Metadata", "Use kotlin.Metadata annotation for code generation")
|
||||
}
|
||||
override fun getPluginInfo(): JadxPluginInfo = JadxPluginInfo(PLUGIN_ID, "Kotlin Metadata", "Use kotlin.Metadata annotation for code generation")
|
||||
|
||||
override fun init(context: JadxPluginContext) {
|
||||
context.registerOptions(options)
|
||||
|
||||
+5
-7
@@ -18,13 +18,11 @@ class KotlinMetadataDecompilePass(
|
||||
private val options: KotlinMetadataOptions,
|
||||
) : JadxDecompilePass {
|
||||
|
||||
override fun getInfo(): JadxPassInfo {
|
||||
return OrderedJadxPassInfo(
|
||||
"KotlinMetadataDecompile",
|
||||
"Use kotlin.Metadata annotation perform various renames",
|
||||
)
|
||||
.before("CodeRenameVisitor")
|
||||
}
|
||||
override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
|
||||
"KotlinMetadataDecompile",
|
||||
"Use kotlin.Metadata annotation perform various renames",
|
||||
)
|
||||
.before("CodeRenameVisitor")
|
||||
|
||||
override fun init(root: RootNode) {
|
||||
}
|
||||
|
||||
+5
-7
@@ -12,13 +12,11 @@ class KotlinMetadataPreparePass(
|
||||
private val options: KotlinMetadataOptions,
|
||||
) : JadxPreparePass {
|
||||
|
||||
override fun getInfo(): JadxPassInfo {
|
||||
return OrderedJadxPassInfo(
|
||||
"KotlinMetadataPrepare",
|
||||
"Use kotlin.Metadata annotation to rename class & package",
|
||||
)
|
||||
.before("RenameVisitor")
|
||||
}
|
||||
override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
|
||||
"KotlinMetadataPrepare",
|
||||
"Use kotlin.Metadata annotation to rename class & package",
|
||||
)
|
||||
.before("RenameVisitor")
|
||||
|
||||
override fun init(root: RootNode) {
|
||||
if (options.isClassAlias) {
|
||||
|
||||
+6
-12
@@ -11,25 +11,19 @@ class KmClassWrapper private constructor(
|
||||
private val kmCls: KmClass,
|
||||
) {
|
||||
|
||||
fun getMethodArgs() =
|
||||
KotlinMetadataUtils.mapMethodArgs(cls, kmCls)
|
||||
fun getMethodArgs() = KotlinMetadataUtils.mapMethodArgs(cls, kmCls)
|
||||
|
||||
fun getFields() =
|
||||
KotlinMetadataUtils.mapFields(cls, kmCls)
|
||||
fun getFields() = KotlinMetadataUtils.mapFields(cls, kmCls)
|
||||
|
||||
fun getCompanion() =
|
||||
KotlinMetadataUtils.mapCompanion(cls, kmCls)
|
||||
fun getCompanion() = KotlinMetadataUtils.mapCompanion(cls, kmCls)
|
||||
|
||||
fun isDataClass() =
|
||||
kmCls.isData
|
||||
fun isDataClass() = kmCls.isData
|
||||
|
||||
// does not require metadata, may be useful for plain java ?
|
||||
fun parseToString() =
|
||||
KotlinUtils.parseToString(cls)
|
||||
fun parseToString() = KotlinUtils.parseToString(cls)
|
||||
|
||||
// does not require metadata, may be useful for plain java ?
|
||||
fun getGetters() =
|
||||
KotlinUtils.findGetters(cls)
|
||||
fun getGetters() = KotlinUtils.findGetters(cls)
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
+5
-9
@@ -48,12 +48,10 @@ private fun IAnnotation.getParamAsStringArray(paramName: String): Array<String>?
|
||||
?.toTypedArray()
|
||||
}
|
||||
|
||||
private fun IAnnotation.getParamAsIntArray(paramName: String): IntArray? {
|
||||
return getParamsAsList(paramName)
|
||||
?.map<EncodedValue, Any?>(EncodedValue::getValue)
|
||||
?.map { it as Int }
|
||||
?.toIntArray()
|
||||
}
|
||||
private fun IAnnotation.getParamAsIntArray(paramName: String): IntArray? = getParamsAsList(paramName)
|
||||
?.map<EncodedValue, Any?>(EncodedValue::getValue)
|
||||
?.map { it as Int }
|
||||
?.toIntArray()
|
||||
|
||||
private fun IAnnotation.getParamAsInt(paramName: String): Int? {
|
||||
val encodedValue = values[paramName]
|
||||
@@ -67,6 +65,4 @@ private fun IAnnotation.getParamAsString(paramName: String): String? {
|
||||
return encodedValue?.value?.let { it as String }
|
||||
}
|
||||
|
||||
fun ClassNode.getKotlinClassMetadata(): KotlinClassMetadata? {
|
||||
return getMetadata()?.let(KotlinClassMetadata::readLenient)
|
||||
}
|
||||
fun ClassNode.getKotlinClassMetadata(): KotlinClassMetadata? = getMetadata()?.let(KotlinClassMetadata::readLenient)
|
||||
|
||||
+7
-11
@@ -33,14 +33,12 @@ object KotlinUtils {
|
||||
}
|
||||
}
|
||||
|
||||
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 getFieldGetterMethod(cls: ClassNode, field: FieldInfo): MethodNode? = 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 {
|
||||
@@ -84,7 +82,5 @@ object KotlinUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDefaultMethodAlias(alias: String): String {
|
||||
return "$alias\$default"
|
||||
}
|
||||
private fun getDefaultMethodAlias(alias: String): String = "$alias\$default"
|
||||
}
|
||||
|
||||
+2
-3
@@ -5,6 +5,5 @@ import org.slf4j.LoggerFactory
|
||||
|
||||
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) =
|
||||
runCatching(block)
|
||||
.onFailure { LOG.error(msg.orEmpty(), it) }
|
||||
inline fun <reified T : Any, R> T.runCatchingLog(msg: String? = null, block: () -> R) = runCatching(block)
|
||||
.onFailure { LOG.error(msg.orEmpty(), it) }
|
||||
|
||||
+10
-16
@@ -124,23 +124,17 @@ class ToStringParser private constructor(mthToString: MethodNode) {
|
||||
)
|
||||
}
|
||||
|
||||
private fun isStartStringBuilder(inst: InsnNode): Boolean {
|
||||
return inst is ConstructorInsn &&
|
||||
inst.isNewInstance &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER
|
||||
}
|
||||
private fun isStartStringBuilder(inst: InsnNode): Boolean = inst is ConstructorInsn &&
|
||||
inst.isNewInstance &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER
|
||||
|
||||
private fun isAppendInvoke(inst: InsnNode): Boolean {
|
||||
return inst is InvokeNode &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
|
||||
inst.callMth.name == "append" &&
|
||||
inst.argsCount == 2
|
||||
}
|
||||
private fun isAppendInvoke(inst: InsnNode): Boolean = inst is InvokeNode &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
|
||||
inst.callMth.name == "append" &&
|
||||
inst.argsCount == 2
|
||||
|
||||
private fun isToString(inst: InsnNode): Boolean {
|
||||
return inst is InvokeNode &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
|
||||
inst.callMth.shortId == Consts.MTH_TOSTRING_SIGNATURE
|
||||
}
|
||||
private fun isToString(inst: InsnNode): Boolean = inst is InvokeNode &&
|
||||
inst.callMth.declClass.fullName == Consts.CLASS_STRING_BUILDER &&
|
||||
inst.callMth.shortId == Consts.MTH_TOSTRING_SIGNATURE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,6 @@ class TestKotlinMetadata : SmaliTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertThatClass(): JadxCodeAssertions =
|
||||
assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinMetadata", "a"))
|
||||
.code()
|
||||
private fun assertThatClass(): JadxCodeAssertions = assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinMetadata", "a"))
|
||||
.code()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@ plugins {
|
||||
dependencies {
|
||||
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")
|
||||
|
||||
testRuntimeOnly(project(":jadx-plugins:jadx-smali-input"))
|
||||
|
||||
+1
-3
@@ -14,9 +14,7 @@ class KotlinSmapOptions : BasePluginOptionsBuilder() {
|
||||
.setter { isClassAliasSourceDbg = it }
|
||||
}
|
||||
|
||||
fun isClassSourceDbg(): Boolean {
|
||||
return isClassAliasSourceDbg
|
||||
}
|
||||
fun isClassSourceDbg(): Boolean = isClassAliasSourceDbg
|
||||
|
||||
companion object {
|
||||
const val CLASS_ALIAS_SOURCE_DBG_OPT = "$PLUGIN_ID.class-alias-source-dbg"
|
||||
|
||||
+1
-3
@@ -9,9 +9,7 @@ class KotlinSmapPlugin : JadxPlugin {
|
||||
|
||||
private val options = KotlinSmapOptions()
|
||||
|
||||
override fun getPluginInfo(): JadxPluginInfo {
|
||||
return JadxPluginInfo(PLUGIN_ID, "Kotlin SMAP", "Use kotlin.SourceDebugExtension annotation for rename class alias")
|
||||
}
|
||||
override fun getPluginInfo(): JadxPluginInfo = JadxPluginInfo(PLUGIN_ID, "Kotlin SMAP", "Use kotlin.SourceDebugExtension annotation for rename class alias")
|
||||
|
||||
override fun init(context: JadxPluginContext) {
|
||||
context.registerOptions(options)
|
||||
|
||||
+11
-18
@@ -33,12 +33,11 @@ class SMAP(val fileMappings: List<FileMapping>) {
|
||||
class FileMapping(val name: String, val path: String) {
|
||||
val lineMappings = arrayListOf<RangeMapping>()
|
||||
|
||||
fun toSourceInfo(): SourceInfo =
|
||||
SourceInfo(
|
||||
name,
|
||||
path,
|
||||
lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) },
|
||||
)
|
||||
fun toSourceInfo(): SourceInfo = SourceInfo(
|
||||
name,
|
||||
path,
|
||||
lineMappings.fold(0) { result, mapping -> max(result, mapping.source + mapping.range - 1) },
|
||||
)
|
||||
|
||||
fun mapNewLineNumber(source: Int, currentIndex: Int, callSite: SourcePosition?): Int {
|
||||
// Save some space in the SMAP by reusing (or extending if it's the last one) the existing range.
|
||||
@@ -51,25 +50,19 @@ class FileMapping(val name: String, val path: String) {
|
||||
return mapping.mapSourceToDest(source)
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping =
|
||||
RangeMapping(source, dest, range, callSite, parent = this).also { lineMappings.add(it) }
|
||||
fun mapNewInterval(source: Int, dest: Int, range: Int, callSite: SourcePosition? = null): RangeMapping = 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) {
|
||||
operator fun contains(destLine: Int): Boolean =
|
||||
dest <= destLine && destLine < dest + range
|
||||
operator fun contains(destLine: Int): Boolean = dest <= destLine && destLine < dest + range
|
||||
|
||||
fun hasMappingForSource(sourceLine: Int): Boolean =
|
||||
source <= sourceLine && sourceLine < source + range
|
||||
fun hasMappingForSource(sourceLine: Int): Boolean = source <= sourceLine && sourceLine < source + range
|
||||
|
||||
fun mapDestToSource(destLine: Int): SourcePosition =
|
||||
SourcePosition(source + (destLine - dest), parent.name, parent.path)
|
||||
fun mapDestToSource(destLine: Int): SourcePosition = SourcePosition(source + (destLine - dest), parent.name, parent.path)
|
||||
|
||||
fun mapSourceToDest(sourceLine: Int): Int =
|
||||
dest + (sourceLine - source)
|
||||
fun mapSourceToDest(sourceLine: Int): Int = dest + (sourceLine - source)
|
||||
}
|
||||
|
||||
val RangeMapping.toRange: IntRange
|
||||
|
||||
+5
-7
@@ -12,13 +12,11 @@ class KotlinSourceDebugExtensionPass(
|
||||
private val options: KotlinSmapOptions,
|
||||
) : JadxPreparePass {
|
||||
|
||||
override fun getInfo(): JadxPassInfo {
|
||||
return OrderedJadxPassInfo(
|
||||
"SourceDebugExtensionPrepare",
|
||||
"Use kotlin.jvm.internal.SourceDebugExtension annotation to rename class & package",
|
||||
)
|
||||
.before("RenameVisitor")
|
||||
}
|
||||
override fun getInfo(): JadxPassInfo = OrderedJadxPassInfo(
|
||||
"SourceDebugExtensionPrepare",
|
||||
"Use kotlin.jvm.internal.SourceDebugExtension annotation to rename class & package",
|
||||
)
|
||||
.before("RenameVisitor")
|
||||
|
||||
override fun init(root: RootNode) {
|
||||
if (options.isClassAliasSourceDbg) {
|
||||
|
||||
+8
-9
@@ -22,12 +22,11 @@ import jadx.plugins.kotlin.smap.model.KOTLIN_STRATA_NAME
|
||||
import jadx.plugins.kotlin.smap.model.SMAP
|
||||
|
||||
object SMAPParser {
|
||||
fun parseOrNull(mappingInfo: String): SMAP? =
|
||||
if (mappingInfo.isNotEmpty()) {
|
||||
parseStratum(mappingInfo, KOTLIN_STRATA_NAME, parseStratum(mappingInfo, KOTLIN_DEBUG_STRATA_NAME, null))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
fun parseOrNull(mappingInfo: String): SMAP? = if (mappingInfo.isNotEmpty()) {
|
||||
parseStratum(mappingInfo, KOTLIN_STRATA_NAME, parseStratum(mappingInfo, KOTLIN_DEBUG_STRATA_NAME, null))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private class SMAPTokenizer(private val text: String, private val headerString: String) : Iterator<String> {
|
||||
|
||||
@@ -55,9 +54,7 @@ object SMAPParser {
|
||||
pos++
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return currentLine != null
|
||||
}
|
||||
override fun hasNext(): Boolean = currentLine != null
|
||||
|
||||
override fun next(): String {
|
||||
val res = currentLine ?: throw NoSuchElementException()
|
||||
@@ -105,7 +102,9 @@ object SMAPParser {
|
||||
val range = when {
|
||||
// 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()
|
||||
|
||||
sourceRangeSeparator != destSeparator -> line.substring(sourceRangeSeparator + 1, destSeparator).toInt()
|
||||
|
||||
else -> 1
|
||||
}
|
||||
// Here we assume that each range in `Kotlin` is entirely within at most one range in `KotlinDebug`.
|
||||
|
||||
+2
-3
@@ -28,7 +28,6 @@ class TestSourceDebugExtension : SmaliTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertThatClass(): JadxCodeAssertions =
|
||||
assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinSourceDebugExtension", "C6"))
|
||||
.code()
|
||||
private fun assertThatClass(): JadxCodeAssertions = assertThat(getClassNodeFromSmaliFiles("deobf", "TestKotlinSourceDebugExtension", "C6"))
|
||||
.code()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user