4
4
5
5
package kotlinx.coroutines.validator
6
6
7
- import org.junit.*
8
- import org.junit.Assert.assertTrue
7
+ import org.junit.Test
8
+ import org.objectweb.asm.*
9
+ import org.objectweb.asm.ClassReader.*
10
+ import org.objectweb.asm.ClassWriter.*
11
+ import org.objectweb.asm.Opcodes.*
9
12
import java.util.jar.*
13
+ import kotlin.test.*
10
14
11
15
class MavenPublicationAtomicfuValidator {
12
16
private val ATOMIC_FU_REF = " Lkotlinx/atomicfu/" .toByteArray()
17
+ private val KOTLIN_METADATA_DESC = " Lkotlin/Metadata;"
13
18
14
19
@Test
15
20
fun testNoAtomicfuInClasspath () {
@@ -34,19 +39,39 @@ class MavenPublicationAtomicfuValidator {
34
39
for (e in entries()) {
35
40
if (! e.name.endsWith(" .class" )) continue
36
41
val bytes = getInputStream(e).use { it.readBytes() }
37
- loop@for (i in 0 until bytes.size - ATOMIC_FU_REF .size) {
38
- for (j in 0 until ATOMIC_FU_REF .size) {
39
- if (bytes[i + j] != ATOMIC_FU_REF [j]) continue @loop
40
- }
42
+ // The atomicfu compiler plugin does not remove atomic properties from metadata,
43
+ // so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata.
44
+ // This may be reverted after the fix in the compiler plugin transformer (for Kotlin 1.8.0).
45
+ val outBytes = bytes.eraseMetadata()
46
+ if (outBytes.checkBytes()) {
41
47
foundClasses + = e.name // report error at the end with all class names
42
- break @loop
43
48
}
44
49
}
45
50
if (foundClasses.isNotEmpty()) {
46
51
error(" Found references to atomicfu in jar file $name in the following class files: ${
47
- foundClasses.joinToString(" " ) { " \n\t\t " + it }
52
+ foundClasses.joinToString(" " ) { " \n\t\t " + it }
48
53
} " )
49
54
}
50
55
close()
51
56
}
57
+
58
+ private fun ByteArray.checkBytes (): Boolean {
59
+ loop@for (i in 0 until this .size - ATOMIC_FU_REF .size) {
60
+ for (j in 0 until ATOMIC_FU_REF .size) {
61
+ if (this [i + j] != ATOMIC_FU_REF [j]) continue @loop
62
+ }
63
+ return true
64
+ }
65
+ return false
66
+ }
67
+
68
+ private fun ByteArray.eraseMetadata (): ByteArray {
69
+ val cw = ClassWriter (COMPUTE_MAXS or COMPUTE_FRAMES )
70
+ ClassReader (this ).accept(object : ClassVisitor (ASM9 , cw) {
71
+ override fun visitAnnotation (descriptor : String? , visible : Boolean ): AnnotationVisitor ? {
72
+ return if (descriptor == KOTLIN_METADATA_DESC ) null else super .visitAnnotation(descriptor, visible)
73
+ }
74
+ }, SKIP_FRAMES )
75
+ return cw.toByteArray()
76
+ }
52
77
}
0 commit comments