aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormvicsokolova <82594708+mvicsokolova@users.noreply.github.com>2024-02-29 13:55:10 +0100
committerGitHub <noreply@github.com>2024-02-29 13:55:10 +0100
commit37b4bdfdef64a9a0f16f32119d364e32e6751d05 (patch)
treec4065c269123d323b43279861320457e23668d8a
parentc945b3a08434e8f863d066e245d41b78003c33bc (diff)
downloadkotlinx.atomicfu-37b4bdfdef64a9a0f16f32119d364e32e6751d05.tar.gz
Replace SynchronizedObject reference with kotlin/Any in class Metadata (#404)
MetadataTransformer: replace kotlinx/atomicfu/SynchronizedObject reference with kotlin/Any in class Metadata. See: https://youtrack.jetbrains.com/issue/KT-63413
-rw-r--r--atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt3
-rw-r--r--integration-testing/examples/multi-module-test/consumer/build.gradle.kts40
-rw-r--r--integration-testing/examples/multi-module-test/consumer/src/jvmMain/kotlin/Main.kt12
-rw-r--r--integration-testing/examples/multi-module-test/gradle.properties4
-rw-r--r--integration-testing/examples/multi-module-test/producer/build.gradle.kts43
-rw-r--r--integration-testing/examples/multi-module-test/producer/src/jvmMain/kotlin/DebugTrace.kt4
-rw-r--r--integration-testing/examples/multi-module-test/settings.gradle.kts21
-rw-r--r--integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/MultiModuleTest.kt30
-rw-r--r--integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/smoke/ArtifactCheckerSmokeTest.kt4
-rw-r--r--integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/framework/checker/ArtifactChecker.kt42
10 files changed, 187 insertions, 16 deletions
diff --git a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt
index ea393e4..2b32a5d 100644
--- a/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt
+++ b/atomicfu-transformer/src/main/kotlin/kotlinx/atomicfu/transformer/MetadataTransformer.kt
@@ -77,6 +77,9 @@ class MetadataTransformer(
// Skip supertype if it is SynchronizedObject (it is an alias to Any)
supertypes.forEach { type ->
if (type.abbreviatedType?.classifier == SynchronizedObjectAlias) {
+ KmType().apply {
+ visitClass("kotlin/Any")
+ }.accept(super.visitSupertype(flagsOf(Flag.IS_PUBLIC, Flag.IS_OPEN))!!)
transformed = true
} else
type.accept(super.visitSupertype(type.flags)!!)
diff --git a/integration-testing/examples/multi-module-test/consumer/build.gradle.kts b/integration-testing/examples/multi-module-test/consumer/build.gradle.kts
new file mode 100644
index 0000000..6e66bb4
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/consumer/build.gradle.kts
@@ -0,0 +1,40 @@
+/*
+ *
+ * * Copyright 2016-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ *
+ */
+
+plugins {
+ kotlin("multiplatform") version libs.versions.kotlinVersion.get()
+ application
+}
+
+repositories {
+ mavenCentral()
+}
+
+kotlin {
+ jvmToolchain(11)
+
+ jvm {
+ withJava()
+ }
+
+ sourceSets {
+ all {
+ languageSettings.apply {
+ languageVersion = "2.0"
+ }
+ }
+
+ val commonMain by getting {
+ dependencies {
+ implementation(project(":producer"))
+ }
+ }
+ }
+}
+
+application {
+ mainClass.set("MainKt")
+}
diff --git a/integration-testing/examples/multi-module-test/consumer/src/jvmMain/kotlin/Main.kt b/integration-testing/examples/multi-module-test/consumer/src/jvmMain/kotlin/Main.kt
new file mode 100644
index 0000000..88cbf22
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/consumer/src/jvmMain/kotlin/Main.kt
@@ -0,0 +1,12 @@
+val debugTrace: DebugTrace? get() = null
+
+inline fun <R> withClue(clue: Any?, thunk: () -> R): R {
+ println("clue: $clue")
+ return thunk()
+}
+
+fun main() {
+ withClue(debugTrace ?: "dcdc") {
+ println("dvdvd")
+ }
+}
diff --git a/integration-testing/examples/multi-module-test/gradle.properties b/integration-testing/examples/multi-module-test/gradle.properties
new file mode 100644
index 0000000..756c4f1
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/gradle.properties
@@ -0,0 +1,4 @@
+kotlin_version=1.9.21
+atomicfu_version=0.23.2-SNAPSHOT
+
+org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
diff --git a/integration-testing/examples/multi-module-test/producer/build.gradle.kts b/integration-testing/examples/multi-module-test/producer/build.gradle.kts
new file mode 100644
index 0000000..802080a
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/producer/build.gradle.kts
@@ -0,0 +1,43 @@
+buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ }
+
+ dependencies {
+ val atomicfuVersion = libs.versions.atomicfuVersion.get()
+ classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfuVersion")
+ }
+}
+
+plugins {
+ kotlin("multiplatform") version libs.versions.kotlinVersion.get()
+}
+
+apply(plugin = "kotlinx-atomicfu")
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+kotlin {
+ jvmToolchain(11)
+
+ jvm()
+
+ sourceSets {
+ all {
+ languageSettings.apply {
+ languageVersion = "2.0"
+ }
+ }
+
+ // This is necessary for now, due to the problem with dependency configuration, see #403
+ val jvmMain by getting {
+ dependencies {
+ api("org.jetbrains.kotlinx:atomicfu:0.23.2")
+ }
+ }
+ }
+}
diff --git a/integration-testing/examples/multi-module-test/producer/src/jvmMain/kotlin/DebugTrace.kt b/integration-testing/examples/multi-module-test/producer/src/jvmMain/kotlin/DebugTrace.kt
new file mode 100644
index 0000000..2eeada7
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/producer/src/jvmMain/kotlin/DebugTrace.kt
@@ -0,0 +1,4 @@
+import kotlinx.atomicfu.*
+import kotlinx.atomicfu.locks.SynchronizedObject
+
+class DebugTrace : SynchronizedObject()
diff --git a/integration-testing/examples/multi-module-test/settings.gradle.kts b/integration-testing/examples/multi-module-test/settings.gradle.kts
new file mode 100644
index 0000000..7ec4476
--- /dev/null
+++ b/integration-testing/examples/multi-module-test/settings.gradle.kts
@@ -0,0 +1,21 @@
+pluginManagement {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ versionCatalogs {
+ create("libs") {
+ version("atomicfuVersion", providers.gradleProperty("atomicfu_version").orNull)
+ version("kotlinVersion", providers.gradleProperty("kotlin_version").orNull)
+ }
+ }
+}
+
+include(":producer", ":consumer")
+
+rootProject.name = "multi-module-test"
diff --git a/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/MultiModuleTest.kt b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/MultiModuleTest.kt
new file mode 100644
index 0000000..68b7e72
--- /dev/null
+++ b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/MultiModuleTest.kt
@@ -0,0 +1,30 @@
+package kotlinx.atomicfu.gradle.plugin.test.cases
+
+import kotlinx.atomicfu.gradle.plugin.test.framework.checker.buildAndCheckBytecode
+import kotlinx.atomicfu.gradle.plugin.test.framework.runner.*
+import kotlin.test.*
+
+/**
+ * This test checks kotlinx-atomicfu plugin application to one module within a project containing multiple modules.
+ *
+ * `multi-module-test` is also a reproducer for the problem with leftovers of atomicfu references in Metadata, see KT-63413
+ */
+class MultiModuleTest {
+ private val multiModuleTest: GradleBuild = createGradleBuildFromSources("multi-module-test")
+
+ @Test
+ fun testMppWithDisabledJvmIrTransformation() {
+ multiModuleTest.enableJvmIrTransformation = false
+ val buildResult = multiModuleTest.cleanAndBuild()
+ assertTrue(buildResult.isSuccessful, buildResult.output)
+ multiModuleTest.buildAndCheckBytecode()
+ }
+
+ @Test
+ fun testMppWithEnabledJvmIrTransformation() {
+ multiModuleTest.enableJvmIrTransformation = true
+ val buildResult = multiModuleTest.cleanAndBuild()
+ assertTrue(buildResult.isSuccessful, buildResult.output)
+ multiModuleTest.buildAndCheckBytecode()
+ }
+}
diff --git a/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/smoke/ArtifactCheckerSmokeTest.kt b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/smoke/ArtifactCheckerSmokeTest.kt
index a9c5b1c..aceda89 100644
--- a/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/smoke/ArtifactCheckerSmokeTest.kt
+++ b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/cases/smoke/ArtifactCheckerSmokeTest.kt
@@ -66,7 +66,7 @@ class ArtifactCheckerSmokeTest {
" d2=[\"LIntArithmetic;\",\"\",\"()V\",\"_x\",\"Lkotlinx/atomicfu/AtomicInt;\",\"doWork\",\"\",\"finalValue\",\"\",\"jvm-sample\"]\n" +
" )"
- override fun checkReferences() {
+ override fun checkReferences(buildDir: File) {
assertTrue(atomicfuString.toByteArray().findAtomicfuRef())
assertFalse(noAtomicfuString.toByteArray().findAtomicfuRef())
assertTrue(metadataString.toByteArray().findAtomicfuRef())
@@ -77,6 +77,6 @@ class ArtifactCheckerSmokeTest {
@Test
fun testAtomicfuReferenciesLookup() {
- checker.checkReferences()
+ checker.checkClassesInBuildDirectories()
}
}
diff --git a/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/framework/checker/ArtifactChecker.kt b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/framework/checker/ArtifactChecker.kt
index 4f504fc..799c077 100644
--- a/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/framework/checker/ArtifactChecker.kt
+++ b/integration-testing/src/functionalTest/kotlin/kotlinx.atomicfu.gradle.plugin.test/framework/checker/ArtifactChecker.kt
@@ -18,12 +18,13 @@ internal abstract class ArtifactChecker(private val targetDir: File) {
protected val projectName = targetDir.name.substringBeforeLast("-")
- val buildDir
- get() = targetDir.resolve("build").also {
- require(it.exists() && it.isDirectory) { "Could not find `build/` directory in the target directory of the project $projectName: ${targetDir.path}" }
+ fun checkClassesInBuildDirectories() {
+ targetDir.walkTopDown().filter { it.isDirectory && it.name == "build" }.forEach {
+ checkReferences(it)
}
+ }
- abstract fun checkReferences()
+ protected abstract fun checkReferences(buildDir: File)
protected fun ByteArray.findAtomicfuRef(): Boolean {
loop@for (i in 0 .. this.size - ATOMIC_FU_REF.size) {
@@ -36,14 +37,27 @@ internal abstract class ArtifactChecker(private val targetDir: File) {
}
}
-private class BytecodeChecker(targetDir: File) : ArtifactChecker(targetDir) {
+private class BytecodeChecker(private val gradleBuild: GradleBuild) : ArtifactChecker(gradleBuild.targetDir) {
- override fun checkReferences() {
- val atomicfuDir = buildDir.resolve("classes/atomicfu/")
- (if (atomicfuDir.exists() && atomicfuDir.isDirectory) atomicfuDir else buildDir).let {
- it.walkBottomUp().filter { it.isFile && it.name.endsWith(".class") }.forEach { clazz ->
- assertFalse(clazz.readBytes().eraseMetadata().findAtomicfuRef(), "Found kotlinx/atomicfu in class file ${clazz.path}")
+ override fun checkReferences(buildDir: File) {
+ // Do not check metadata for kotlinx-atomicfu references if the compiler plugin is applied.
+ if (gradleBuild.enableJvmIrTransformation) {
+ buildDir.walkDirAndCheckBytecode(skipMetadata = true)
+ } else {
+ val atomicfuDir = buildDir.resolve("classes/atomicfu/")
+ if (atomicfuDir.exists() && atomicfuDir.isDirectory) {
+ atomicfuDir.walkDirAndCheckBytecode(skipMetadata = false)
+ }
+ }
+
+ }
+
+ private fun File.walkDirAndCheckBytecode(skipMetadata: Boolean) {
+ walkBottomUp().filter { it.isFile && it.name.endsWith(".class") }.forEach { clazz ->
+ val atomicfuRefFound = clazz.readBytes().let {
+ if (skipMetadata) it.eraseMetadata().findAtomicfuRef() else it.findAtomicfuRef()
}
+ assertFalse(atomicfuRefFound, "Found kotlinx/atomicfu in class file ${clazz.path}")
}
}
@@ -51,7 +65,7 @@ private class BytecodeChecker(targetDir: File) : ArtifactChecker(targetDir) {
// so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata.
// This may be reverted after the fix in the compiler plugin transformer (See #254).
private fun ByteArray.eraseMetadata(): ByteArray {
- val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)
+ val cw = ClassWriter(0)
ClassReader(this).accept(object : ClassVisitor(Opcodes.ASM9, cw) {
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
return if (descriptor == KOTLIN_METADATA_DESC) null else super.visitAnnotation(descriptor, visible)
@@ -92,7 +106,7 @@ private class KlibChecker(targetDir: File) : ArtifactChecker(targetDir) {
return output.toString()
}
- override fun checkReferences() {
+ override fun checkReferences(buildDir: File) {
val classesDir = buildDir.resolve("classes/kotlin/")
if (classesDir.exists() && classesDir.isDirectory) {
classesDir.walkBottomUp().singleOrNull { it.isFile && it.name == "$projectName.klib" }?.let { klib ->
@@ -112,12 +126,12 @@ private class KlibChecker(targetDir: File) : ArtifactChecker(targetDir) {
internal fun GradleBuild.buildAndCheckBytecode() {
val buildResult = cleanAndBuild()
require(buildResult.isSuccessful) { "Build of the project $projectName failed:\n ${buildResult.output}" }
- BytecodeChecker(this.targetDir).checkReferences()
+ BytecodeChecker(this).checkClassesInBuildDirectories()
}
// TODO: klib checks are skipped for now because of this problem KT-61143
internal fun GradleBuild.buildAndCheckNativeKlib() {
val buildResult = cleanAndBuild()
require(buildResult.isSuccessful) { "Build of the project $projectName failed:\n ${buildResult.output}" }
- KlibChecker(this.targetDir).checkReferences()
+ KlibChecker(this.targetDir).checkClassesInBuildDirectories()
}