Binary compatibility validator is now an external tool
Use its code from a dependency.
This commit is contained in:
@@ -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')
|
||||
|
||||
|
||||
-104
@@ -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<String>) {
|
||||
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<ClassBinarySignature> =
|
||||
getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityFilter)
|
||||
|
||||
fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> {
|
||||
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<ClassBinarySignature>.filterOutNonPublic(nonPublicPackages: List<String> = emptyList()): List<ClassBinarySignature> {
|
||||
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<ClassBinarySignature>.dump() = dump(to = System.out)
|
||||
|
||||
fun <T : Appendable> List<ClassBinarySignature>.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")
|
||||
}}
|
||||
|
||||
-189
@@ -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<String>,
|
||||
val memberSignatures: List<MemberBinarySignature>,
|
||||
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 == "<init>" && 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 == "<init>" && "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<MemberBinarySignature>(
|
||||
{ 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<String> = 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<Any>.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<AnnotationNode>?, invisibleAnnotations: List<AnnotationNode>?, 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)
|
||||
-102
@@ -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<Int>?)?.toIntArray(),
|
||||
bytecodeVersion = (get("bv") as List<Int>?)?.toIntArray(),
|
||||
data1 = (get("d1") as List<String>?)?.toTypedArray(),
|
||||
data2 = (get("d2") as List<String>?)?.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<MemberVisibility>()
|
||||
|
||||
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<KmTypeParameter>.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<ClassNode>.readKotlinVisibilities(): Map<String, ClassVisibility> =
|
||||
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)
|
||||
}
|
||||
}
|
||||
-43
@@ -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<JvmMemberSignature, MemberVisibility>,
|
||||
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<ClassVisibility>()
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -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")
|
||||
|
||||
|
||||
+2
-2
@@ -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")
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user