From a95f205c1a2560b428a7c0196c92103d22babd3f Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Thu, 20 Feb 2020 21:22:02 +0300 Subject: [PATCH] Binary compatibility validator is now an external tool Use its code from a dependency. --- .../build.gradle | 8 +- .../PublicApiDump.kt | 104 ---------- .../org.jetbrains.kotlin.tools/asmUtils.kt | 189 ------------------ .../kotlinMetadataVisibilities.kt | 102 ---------- .../kotlinVisibilities.kt | 43 ---- .../CasesPublicAPITest.kt | 4 +- .../RuntimePublicAPITest.kt | 4 +- .../org.jetbrains.kotlin.tools.tests/utils.kt | 2 +- 8 files changed, 6 insertions(+), 450 deletions(-) delete mode 100644 libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/PublicApiDump.kt delete mode 100644 libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/asmUtils.kt delete mode 100644 libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinMetadataVisibilities.kt delete mode 100644 libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinVisibilities.kt diff --git a/libraries/tools/binary-compatibility-validator/build.gradle b/libraries/tools/binary-compatibility-validator/build.gradle index 0d604f7cef0..50d1fc8a2c3 100644 --- a/libraries/tools/binary-compatibility-validator/build.gradle +++ b/libraries/tools/binary-compatibility-validator/build.gradle @@ -6,13 +6,7 @@ configurations { } dependencies { - compile project(':kotlin-stdlib') - compileOnly project(':kotlinx-metadata') - compileOnly project(':kotlinx-metadata-jvm') - compile 'org.ow2.asm:asm:6.0' - compile 'org.ow2.asm:asm-tree:6.0' - - runtime project(path: ':kotlinx-metadata-jvm', configuration: 'runtime') + compile("org.jetbrains.kotlinx:binary-compatibility-validator:0.2.3") testCompile project(':kotlin-test:kotlin-test-junit') diff --git a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/PublicApiDump.kt b/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/PublicApiDump.kt deleted file mode 100644 index 314f318b44d..00000000000 --- a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/PublicApiDump.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.tools - -import kotlinx.metadata.jvm.JvmFieldSignature -import kotlinx.metadata.jvm.JvmMethodSignature -import org.objectweb.asm.* -import org.objectweb.asm.tree.* -import java.io.InputStream -import java.util.jar.JarFile - -fun main(args: Array) { - val src = args[0] - println(src) - println("------------------\n"); - getBinaryAPI(JarFile(src)).filterOutNonPublic().dump() -} - - -fun JarFile.classEntries() = Sequence { entries().iterator() }.filter { - !it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/") -} - -fun getBinaryAPI(jar: JarFile, visibilityFilter: (String) -> Boolean = { true }): List = - getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityFilter) - -fun getBinaryAPI(classStreams: Sequence, visibilityFilter: (String) -> Boolean = { true }): List { - val classNodes = classStreams.map { it.use { stream -> - val classNode = ClassNode() - ClassReader(stream).accept(classNode, ClassReader.SKIP_CODE) - classNode - }} - - val visibilityMapNew = classNodes.readKotlinVisibilities().filterKeys(visibilityFilter) - - return classNodes - .map { with(it) { - val metadata = kotlinMetadata - val mVisibility = visibilityMapNew[name] - val classAccess = AccessFlags(effectiveAccess and Opcodes.ACC_STATIC.inv()) - - val supertypes = listOf(superName) - "java/lang/Object" + interfaces.sorted() - - val memberSignatures = ( - fields.map { with(it) { FieldBinarySignature(JvmFieldSignature(name, desc), isPublishedApi(), AccessFlags(access)) } } + - methods.map { with(it) { MethodBinarySignature(JvmMethodSignature(name, desc), isPublishedApi(), AccessFlags(access)) } } - ).filter { - it.isEffectivelyPublic(classAccess, mVisibility) - } - - ClassBinarySignature(name, superName, outerClassName, supertypes, memberSignatures, classAccess, - isEffectivelyPublic(mVisibility), metadata.isFileOrMultipartFacade() || isDefaultImpls(metadata) - ) - }} - .asIterable() - .sortedBy { it.name } -} - - - -fun List.filterOutNonPublic(nonPublicPackages: List = emptyList()): List { - val nonPublicPaths = nonPublicPackages.map { it.replace('.', '/') + '/' } - val classByName = associateBy { it.name } - - fun ClassBinarySignature.isInNonPublicPackage() = - nonPublicPaths.any { name.startsWith(it) } - - fun ClassBinarySignature.isPublicAndAccessible(): Boolean = - isEffectivelyPublic && - (outerName == null || classByName[outerName]?.let { outerClass -> - !(this.access.isProtected && outerClass.access.isFinal) - && outerClass.isPublicAndAccessible() - } ?: true) - - fun supertypes(superName: String) = generateSequence({ classByName[superName] }, { classByName[it.superName] }) - - fun ClassBinarySignature.flattenNonPublicBases(): ClassBinarySignature { - - val nonPublicSupertypes = supertypes(superName).takeWhile { !it.isPublicAndAccessible() }.toList() - if (nonPublicSupertypes.isEmpty()) - return this - - val inheritedStaticSignatures = nonPublicSupertypes.flatMap { it.memberSignatures.filter { it.access.isStatic }} - - // not covered the case when there is public superclass after chain of private superclasses - return this.copy(memberSignatures = memberSignatures + inheritedStaticSignatures, supertypes = supertypes - superName) - } - - return filter { !it.isInNonPublicPackage() && it.isPublicAndAccessible() } - .map { it.flattenNonPublicBases() } - .filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty()} -} - -fun List.dump() = dump(to = System.out) - -fun List.dump(to: T): T = to.apply { this@dump.forEach { - append(it.signature).appendln(" {") - it.memberSignatures.sortedWith(MEMBER_SORT_ORDER).forEach { append("\t").appendln(it.signature) } - appendln("}\n") -}} - diff --git a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/asmUtils.kt b/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/asmUtils.kt deleted file mode 100644 index 6abe23409ea..00000000000 --- a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/asmUtils.kt +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.tools - -import kotlinx.metadata.jvm.* -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.* - -val ACCESS_NAMES = mapOf( - Opcodes.ACC_PUBLIC to "public", - Opcodes.ACC_PROTECTED to "protected", - Opcodes.ACC_PRIVATE to "private", - Opcodes.ACC_STATIC to "static", - Opcodes.ACC_FINAL to "final", - Opcodes.ACC_ABSTRACT to "abstract", - Opcodes.ACC_SYNTHETIC to "synthetic", - Opcodes.ACC_INTERFACE to "interface", - Opcodes.ACC_ANNOTATION to "annotation" -) - -data class ClassBinarySignature( - val name: String, - val superName: String, - val outerName: String?, - val supertypes: List, - val memberSignatures: List, - val access: AccessFlags, - val isEffectivelyPublic: Boolean, - val isNotUsedWhenEmpty: Boolean -) { - val signature: String - get() = "${access.getModifierString()} class $name" + if (supertypes.isEmpty()) "" else " : ${supertypes.joinToString()}" -} - - -interface MemberBinarySignature { - val jvmMember: JvmMemberSignature - val name: String get() = jvmMember.name - val desc: String get() = jvmMember.desc - val access: AccessFlags - val isPublishedApi: Boolean - - fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?) = - access.isPublic && !(access.isProtected && classAccess.isFinal) - && (findMemberVisibility(classVisibility)?.isPublic(isPublishedApi) ?: true) - - fun findMemberVisibility(classVisibility: ClassVisibility?): MemberVisibility? { - return classVisibility?.findMember(jvmMember) - } - - val signature: String -} - -data class MethodBinarySignature( - override val jvmMember: JvmMethodSignature, - override val isPublishedApi: Boolean, - override val access: AccessFlags -) : MemberBinarySignature { - override val signature: String - get() = "${access.getModifierString()} fun $name $desc" - - override fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?) = - super.isEffectivelyPublic(classAccess, classVisibility) - && !isAccessOrAnnotationsMethod() - && !isDummyDefaultConstructor() - - override fun findMemberVisibility(classVisibility: ClassVisibility?): MemberVisibility? { - return super.findMemberVisibility(classVisibility) ?: classVisibility?.let { alternateDefaultSignature(it.name)?.let(it::findMember) } - } - - private fun isAccessOrAnnotationsMethod() = access.isSynthetic && (name.startsWith("access\$") || name.endsWith("\$annotations")) - - private fun isDummyDefaultConstructor() = access.isSynthetic && name == "" && desc == "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V" - - /** - * Calculates the signature of this method without default parameters - * - * Returns `null` if this method isn't an entry point of a function - * or a constructor with default parameters. - * Returns an incorrect result, if there are more than 31 default parameters. - */ - private fun alternateDefaultSignature(className: String): JvmMethodSignature? { - return when { - !access.isSynthetic -> null - name == "" && "ILkotlin/jvm/internal/DefaultConstructorMarker;" in desc -> - JvmMethodSignature(name, desc.replace("ILkotlin/jvm/internal/DefaultConstructorMarker;", "")) - name.endsWith("\$default") && "ILjava/lang/Object;)" in desc -> - JvmMethodSignature( - name.removeSuffix("\$default"), - desc.replace("ILjava/lang/Object;)", ")").replace("(L$className;", "(") - ) - else -> null - } - } -} - -data class FieldBinarySignature( - override val jvmMember: JvmFieldSignature, - override val isPublishedApi: Boolean, - override val access: AccessFlags -) : MemberBinarySignature { - override val signature: String - get() = "${access.getModifierString()} field $name $desc" - - override fun findMemberVisibility(classVisibility: ClassVisibility?): MemberVisibility? { - return super.findMemberVisibility(classVisibility) - ?: takeIf { access.isStatic }?.let { super.findMemberVisibility(classVisibility?.companionVisibilities) } - } -} - -private val MemberBinarySignature.kind: Int - get() = when (this) { - is FieldBinarySignature -> 1 - is MethodBinarySignature -> 2 - else -> error("Unsupported $this") - } - -val MEMBER_SORT_ORDER = compareBy( - { it.kind }, - { it.name }, - { it.desc } -) - - -data class AccessFlags(val access: Int) { - val isPublic: Boolean get() = isPublic(access) - val isProtected: Boolean get() = isProtected(access) - val isStatic: Boolean get() = isStatic(access) - val isFinal: Boolean get() = isFinal(access) - val isSynthetic: Boolean get() = isSynthetic(access) - - fun getModifiers(): List = ACCESS_NAMES.entries.mapNotNull { if (access and it.key != 0) it.value else null } - fun getModifierString(): String = getModifiers().joinToString(" ") -} - -fun isPublic(access: Int) = access and Opcodes.ACC_PUBLIC != 0 || access and Opcodes.ACC_PROTECTED != 0 -fun isProtected(access: Int) = access and Opcodes.ACC_PROTECTED != 0 -fun isStatic(access: Int) = access and Opcodes.ACC_STATIC != 0 -fun isFinal(access: Int) = access and Opcodes.ACC_FINAL != 0 -fun isSynthetic(access: Int) = access and Opcodes.ACC_SYNTHETIC != 0 - - -fun ClassNode.isEffectivelyPublic(classVisibility: ClassVisibility?) = - isPublic(access) - && !isLocal() - && !isWhenMappings() - && (classVisibility?.isPublic(isPublishedApi()) ?: true) - - -val ClassNode.innerClassNode: InnerClassNode? get() = innerClasses.singleOrNull { it.name == name } -fun ClassNode.isLocal() = innerClassNode?.run { innerName == null && outerName == null} ?: false -fun ClassNode.isInner() = innerClassNode != null -fun ClassNode.isWhenMappings() = isSynthetic(access) && name.endsWith("\$WhenMappings") - -val ClassNode.effectiveAccess: Int get() = innerClassNode?.access ?: access -val ClassNode.outerClassName: String? get() = innerClassNode?.outerName - - -const val publishedApiAnnotationName = "kotlin/PublishedApi" -fun ClassNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null -fun MethodNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null -fun FieldNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null - - -fun ClassNode.isDefaultImpls(metadata: KotlinClassMetadata?) = isInner() && name.endsWith("\$DefaultImpls") && metadata.isSyntheticClass() - - -fun ClassNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) -fun MethodNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) -fun FieldNode.findAnnotation(annotationName: String, includeInvisible: Boolean = false) = findAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) - -operator fun AnnotationNode.get(key: String): Any? = values.annotationValue(key) - -private fun List.annotationValue(key: String): Any? { - for (index in (0 until size / 2)) { - if (this[index * 2] == key) - return this[index * 2 + 1] - } - return null -} - -private fun findAnnotation(annotationName: String, visibleAnnotations: List?, invisibleAnnotations: List?, includeInvisible: Boolean): AnnotationNode? = - visibleAnnotations?.firstOrNull { it.refersToName(annotationName) } - ?: if (includeInvisible) invisibleAnnotations?.firstOrNull { it.refersToName(annotationName) } else null - -fun AnnotationNode.refersToName(name: String) = desc.startsWith('L') && desc.endsWith(';') && desc.regionMatches(1, name, 0, name.length) diff --git a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinMetadataVisibilities.kt b/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinMetadataVisibilities.kt deleted file mode 100644 index 7d50a36dd6f..00000000000 --- a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinMetadataVisibilities.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.tools - -import kotlinx.metadata.* -import kotlinx.metadata.jvm.* -import org.objectweb.asm.tree.ClassNode - -val ClassNode.kotlinMetadata: KotlinClassMetadata? - get() { - val metadata = findAnnotation("kotlin/Metadata", false) ?: return null - @Suppress("UNCHECKED_CAST") - val header = with(metadata) { - KotlinClassHeader( - kind = get("k") as Int?, - metadataVersion = (get("mv") as List?)?.toIntArray(), - bytecodeVersion = (get("bv") as List?)?.toIntArray(), - data1 = (get("d1") as List?)?.toTypedArray(), - data2 = (get("d2") as List?)?.toTypedArray(), - extraString = get("xs") as String?, - packageName = get("pn") as String?, - extraInt = get("xi") as Int? - ) - } - return KotlinClassMetadata.read(header) - } - - -fun KotlinClassMetadata?.isFileOrMultipartFacade() = - this is KotlinClassMetadata.FileFacade || this is KotlinClassMetadata.MultiFileClassFacade - -fun KotlinClassMetadata?.isSyntheticClass() = this is KotlinClassMetadata.SyntheticClass - -fun KotlinClassMetadata.toClassVisibility(classNode: ClassNode): ClassVisibility? { - var flags: Flags? = null - var _facadeClassName: String? = null - val members = mutableListOf() - - fun addMember(signature: JvmMemberSignature?, flags: Flags, isReified: Boolean) { - if (signature != null) { - members.add(MemberVisibility(signature, flags, isReified)) - } - } - - val container: KmDeclarationContainer? = when (this) { - is KotlinClassMetadata.Class -> - toKmClass().also { klass -> - flags = klass.flags - - for (constructor in klass.constructors) { - addMember(constructor.signature, constructor.flags, isReified = false) - } - } - is KotlinClassMetadata.FileFacade -> - toKmPackage() - is KotlinClassMetadata.MultiFileClassPart -> - toKmPackage().also { _facadeClassName = this.facadeClassName } - else -> null - } - - if (container != null) { - fun List.containsReified() = any { Flag.TypeParameter.IS_REIFIED(it.flags) } - - for (function in container.functions) { - addMember(function.signature, function.flags, function.typeParameters.containsReified()) - } - - for (property in container.properties) { - val isReified = property.typeParameters.containsReified() - addMember(property.getterSignature, property.getterFlags, isReified) - addMember(property.setterSignature, property.setterFlags, isReified) - - val fieldVisibility = when { - Flag.Property.IS_LATEINIT(property.flags) -> property.setterFlags - property.getterSignature == null && property.setterSignature == null -> property.flags // JvmField or const case - else -> flagsOf(Flag.IS_PRIVATE) - } - addMember(property.fieldSignature, fieldVisibility, isReified = false) - } - } - - return ClassVisibility(classNode.name, flags, members.associateBy { it.member }, _facadeClassName) -} - -fun ClassNode.toClassVisibility() = kotlinMetadata?.toClassVisibility(this) - -fun Sequence.readKotlinVisibilities(): Map = - mapNotNull { it.toClassVisibility() } - .associateBy { it.name } - .apply { - values.asSequence().filter { it.isCompanion }.forEach { - val containingClassName = it.name.substringBeforeLast('$') - getValue(containingClassName).companionVisibilities = it - } - - values.asSequence().filter { it.facadeClassName != null }.forEach { - getValue(it.facadeClassName!!).partVisibilities.add(it) - } - } diff --git a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinVisibilities.kt b/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinVisibilities.kt deleted file mode 100644 index 4a295fec92f..00000000000 --- a/libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinVisibilities.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.tools - -import kotlinx.metadata.Flag -import kotlinx.metadata.Flags -import kotlinx.metadata.jvm.JvmMemberSignature - -class ClassVisibility( - val name: String, - val flags: Flags?, - val members: Map, - val facadeClassName: String? = null -) { - val visibility get() = flags - val isCompanion: Boolean get() = flags != null && Flag.Class.IS_COMPANION_OBJECT(flags) - - var companionVisibilities: ClassVisibility? = null - val partVisibilities = mutableListOf() -} - -fun ClassVisibility.findMember(signature: JvmMemberSignature): MemberVisibility? = - members[signature] ?: partVisibilities.mapNotNull { it.members[signature] }.firstOrNull() - - -data class MemberVisibility(val member: JvmMemberSignature, val visibility: Flags?, val isReified: Boolean) - -private fun isPublic(visibility: Flags?, isPublishedApi: Boolean) = - visibility == null - || Flag.IS_PUBLIC(visibility) - || Flag.IS_PROTECTED(visibility) - || (isPublishedApi && Flag.IS_INTERNAL(visibility)) - -fun ClassVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi) -fun MemberVisibility.isPublic(isPublishedApi: Boolean) = - // Assuming isReified implies inline - !isReified && isPublic(visibility, isPublishedApi) - - - diff --git a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/CasesPublicAPITest.kt b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/CasesPublicAPITest.kt index 532c0db0e2a..10d77307aee 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/CasesPublicAPITest.kt +++ b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/CasesPublicAPITest.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.tools.tests -import org.jetbrains.kotlin.tools.* +import kotlinx.validation.api.* import org.junit.* import org.junit.rules.TestName import java.io.File @@ -58,7 +58,7 @@ class CasesPublicAPITest { val testClassStreams = testClasses.asSequence().filter { it.name.endsWith(".class") }.map { it.inputStream() } - val api = getBinaryAPI(testClassStreams).filterOutNonPublic() + val api = testClassStreams.loadApiFromJvmClasses().filterOutNonPublic() val target = baseOutputPath.resolve(testClassRelativePath).resolve(testName.methodName + ".txt") diff --git a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/RuntimePublicAPITest.kt b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/RuntimePublicAPITest.kt index d7c1732e98b..3b868370b32 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/RuntimePublicAPITest.kt +++ b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/RuntimePublicAPITest.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.tools.tests -import org.jetbrains.kotlin.tools.* +import kotlinx.validation.api.* import org.junit.Rule import org.junit.Test import org.junit.rules.TestName @@ -51,7 +51,7 @@ class RuntimePublicAPITest { val publicPackageFilter = { className: String -> publicPackagePrefixes.none { className.startsWith(it) } } println("Reading binary API from $jarFile") - val api = getBinaryAPI(JarFile(jarFile), publicPackageFilter).filterOutNonPublic(nonPublicPackages) + val api = JarFile(jarFile).loadApiFromJvmClasses(publicPackageFilter).filterOutNonPublic(nonPublicPackages) val target = File("reference-public-api") .resolve(testName.methodName.replaceCamelCaseWithDashedLowerCase() + ".txt") diff --git a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/utils.kt b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/utils.kt index a581aa6f0cc..c4c842c700c 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/utils.kt +++ b/libraries/tools/binary-compatibility-validator/src/test/kotlin/org.jetbrains.kotlin.tools.tests/utils.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.tools.tests -import org.jetbrains.kotlin.tools.* +import kotlinx.validation.api.* import java.io.File import kotlin.test.assertEquals import kotlin.test.fail