Skip to content

Revised the ProGuard rules and added tests on R8 #3041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@ plugins {

repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev")
// kotlin-dev with space redirector
maven("https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
maven("https://redirector.kotlinlang.org/maven/dev")
// For Dokka that depends on kotlinx-html
maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")
// For local development
mavenLocal()
}

// == common projects settings setup
Expand Down Expand Up @@ -60,14 +53,13 @@ allprojects {
}
repositories {
mavenCentral()
maven("https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
maven("https://redirector.kotlinlang.org/maven/dev")
}
}

// == BCV setup ==
apiValidation {
ignoredProjects.addAll(listOf("benchmark", "guide", "kotlinx-serialization", "kotlinx-serialization-json-tests"))
ignoredProjects.addAll(listOf("benchmark", "guide", "kotlinx-serialization", "kotlinx-serialization-json-tests", "proguard-rules-test"))
@OptIn(ExperimentalBCVApi::class)
klib {
enabled = true
Expand Down Expand Up @@ -163,6 +155,7 @@ val unpublishedProjects
"guide",
"kotlinx-serialization-json-tests",
"proto-test-model",
"proguard-rules-test",
)
val excludedFromBomProjects get() = unpublishedProjects + "kotlinx-serialization-bom"

Expand Down
10 changes: 1 addition & 9 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,8 @@ repositories {
maven("https://oss.sonatype.org/content/repositories/snapshots")
}

// kotlin-dev with space redirector
maven("https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
maven("https://redirector.kotlinlang.org/maven/dev")

maven("https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev")
// For Dokka that depends on kotlinx-html
maven("https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven")

mavenCentral()
mavenLocal()
maven("https://redirector.kotlinlang.org/maven/dev")
}

kotlin {
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/Java9Modularity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ object Java9Modularity {

val taskKotlinLanguageVersion = compilerOptions.languageVersion.orElse(KotlinVersion.DEFAULT)
@OptIn(InternalKotlinGradlePluginApi::class)
@Suppress("DEPRECATION")
if (taskKotlinLanguageVersion.get() < KotlinVersion.KOTLIN_2_0) {
// part of work-around for https://youtrack.jetbrains.com/issue/KT-60541
@Suppress("INVISIBLE_MEMBER")
Expand Down
10 changes: 1 addition & 9 deletions buildSrc/src/main/kotlin/global-compiler-options.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,7 @@ tasks.withType(KotlinCompilationTask::class).configureEach {
null -> true // Werror is enabled by default
else -> throw GradleException("Invalid kotlin_Werror_override value. Use 'enable' or 'disable'")
}

allWarningsAsErrors = werrorEnabled
// Add extra compiler options when -Werror is disabled
if (!werrorEnabled) {
freeCompilerArgs.addAll(
"-Wextra",
"-Xuse-fir-experimental-checkers"
)
}
}
}
}
Expand All @@ -58,4 +50,4 @@ tasks.withType<KotlinCompilationTask<*>>().configureEach {
logger.info("Added Kotlin compiler flags: ${compilerOptions.freeCompilerArgs.get().joinToString(", ")}")
logger.info("allWarningsAsErrors=${compilerOptions.allWarningsAsErrors.get()}")
}
}
}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/kover-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ kover {
}


val uncoveredProjects get() = setOf(":kotlinx-serialization-bom", ":benchmark", ":guide")
val uncoveredProjects get() = setOf(":kotlinx-serialization-bom", ":benchmark", ":guide", ":proguard-rules-test")
// map: variant name -> project path
val projectsForCoverageVerification get() = mapOf("core" to ":kotlinx-serialization-core", "json" to ":kotlinx-serialization-json", "jsonOkio" to ":kotlinx-serialization-json-okio", "cbor" to ":kotlinx-serialization-cbor", "hocon" to ":kotlinx-serialization-hocon", "properties" to ":kotlinx-serialization-properties", "protobuf" to ":kotlinx-serialization-protobuf", "io" to ":kotlinx-serialization-json-io")
16 changes: 12 additions & 4 deletions core/jvmMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,20 @@ private fun <T: Any> Class<T>.findInNamedCompanion(vararg args: KSerializer<Any?
}
}

private fun <T: Any> Class<T>.findNamedCompanionByAnnotation(): Any? {
val companionClass = declaredClasses.firstOrNull { clazz ->
clazz.getAnnotation(NamedCompanion::class.java) != null
private fun <T : Any> Class<T>.findNamedCompanionByAnnotation(): Any? {
// search static field with type marked by kotlinx.serialization.internal.NamedCompanion - it's the companion
// declaredClasses after R8 even if `-keepattributes InnerClasses, EnclosingMethod` is specified, so we use declaredFields
val field = declaredFields.firstOrNull { field ->
Modifier.isStatic(field.modifiers) && field.type.getAnnotation(NamedCompanion::class.java) != null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention in the comment that declaredClasses unavailable after R8

} ?: return null

return companionOrNull(companionClass.simpleName)
// short version of companionOrNull()
return try {
field.isAccessible = true
field.get(null)
} catch (e: Throwable) {
null
}
}

private fun <T: Any> Class<T>.isNotAnnotated(): Boolean {
Expand Down
1 change: 0 additions & 1 deletion integration-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ plugins {

repositories {
mavenCentral()
maven("https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
maven("https://redirector.kotlinlang.org/maven/dev")
mavenLocal {
mavenContent {
Expand Down
1 change: 0 additions & 1 deletion integration-test/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ pluginManagement {
repositories {
mavenCentral()
maven("https://plugins.gradle.org/m2/")
maven("https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
maven("https://redirector.kotlinlang.org/maven/dev")
mavenLocal()
}
Expand Down
13 changes: 5 additions & 8 deletions rules/common.pro
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Keep `Companion` object fields of serializable classes.
# Keep `Companion` object field of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$* Companion;
}
-keepclassmembers @kotlinx.serialization.Serializable class ** {
static ** Companion;
}

# Keep names for named companion object from obfuscation
# Names of a class and of a field are important in lookup of named companion in runtime
-keepnames @kotlinx.serialization.internal.NamedCompanion class *
-if @kotlinx.serialization.internal.NamedCompanion class *
-keepclassmembernames class * {
-keepclassmembers class * {
static <1> *;
}

Expand All @@ -36,7 +34,6 @@
# Don't print notes about potential mistakes or omissions in the configuration for kotlinx-serialization classes
# See also https://github.com/Kotlin/kotlinx.serialization/issues/1900
-dontnote kotlinx.serialization.**

# Serialization core uses `java.lang.ClassValue` for caching inside these specified classes.
# If there is no `java.lang.ClassValue` (for example, in Android), then R8/ProGuard will print a warning.
# However, since in this case they will not be used, we can disable these warnings
Expand Down
4 changes: 4 additions & 0 deletions rules/r8.pro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
-if @kotlinx.serialization.Serializable class **
-keep, allowshrinking, allowoptimization, allowobfuscation, allowaccessmodification class <1>

# Rule to save runtime annotations on named companion class.
# If the R8 full mode is used, annotations are removed from classes-files.
-if @kotlinx.serialization.internal.NamedCompanion class *
-keep, allowshrinking, allowoptimization, allowobfuscation, allowaccessmodification class <1>

# Rule to save INSTANCE field and serializer function for Kotlin serializable objects.
#
Expand Down
Loading