bcv: cleanup the old way of reading kotlin visibilities
This commit is contained in:
@@ -10,7 +10,6 @@ dependencies {
|
||||
compile project(':kotlinx-metadata-jvm')
|
||||
compile 'org.ow2.asm:asm:6.0'
|
||||
compile 'org.ow2.asm:asm-tree:6.0'
|
||||
compile 'com.google.code.gson:gson:2.6.2'
|
||||
testCompile project(':kotlin-test:kotlin-test-junit')
|
||||
|
||||
testArtifacts project(':kotlin-stdlib')
|
||||
|
||||
+22
-21
@@ -1,17 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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 org.objectweb.asm.*
|
||||
import org.objectweb.asm.tree.*
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.util.jar.JarFile
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
var src = args[0]
|
||||
val src = args[0]
|
||||
println(src)
|
||||
println("------------------\n");
|
||||
val visibilities = readKotlinVisibilities(File("""stdlib/target/stdlib-declarations.json"""))
|
||||
getBinaryAPI(JarFile(src), visibilities).filterOutNonPublic().dump()
|
||||
getBinaryAPI(JarFile(src)).filterOutNonPublic().dump()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +22,10 @@ fun JarFile.classEntries() = Sequence { entries().iterator() }.filter {
|
||||
!it.isDirectory && it.name.endsWith(".class") && !it.name.startsWith("META-INF/")
|
||||
}
|
||||
|
||||
fun getBinaryAPI(jar: JarFile, visibilityMap: Map<String, ClassVisibility>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> =
|
||||
getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityMap, visibilityFilter)
|
||||
fun getBinaryAPI(jar: JarFile, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature> =
|
||||
getBinaryAPI(jar.classEntries().map { entry -> jar.getInputStream(entry) }, visibilityFilter)
|
||||
|
||||
fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityMap: Map<String, ClassVisibility>, visibilityFilter: (String) -> Boolean = { true }): List<ClassBinarySignature>
|
||||
{
|
||||
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)
|
||||
@@ -34,7 +36,6 @@ fun getBinaryAPI(classStreams: Sequence<InputStream>, visibilityMap: Map<String,
|
||||
|
||||
return classNodes
|
||||
.map { with(it) {
|
||||
val classVisibility = visibilityMap[name]
|
||||
val metadata = kotlinMetadata
|
||||
val mVisibility = visibilityMapNew[name]
|
||||
val classAccess = AccessFlags(effectiveAccess and Opcodes.ACC_STATIC.inv())
|
||||
@@ -63,14 +64,14 @@ fun List<ClassBinarySignature>.filterOutNonPublic(nonPublicPackages: List<String
|
||||
val classByName = associateBy { it.name }
|
||||
|
||||
fun ClassBinarySignature.isInNonPublicPackage() =
|
||||
nonPublicPaths.any { name.startsWith(it) }
|
||||
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)
|
||||
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] })
|
||||
|
||||
@@ -87,15 +88,15 @@ fun List<ClassBinarySignature>.filterOutNonPublic(nonPublicPackages: List<String
|
||||
}
|
||||
|
||||
return filter { !it.isInNonPublicPackage() && it.isPublicAndAccessible() }
|
||||
.map { it.flattenNonPublicBases() }
|
||||
.filterNot { it.isNotUsedWhenEmpty && it.memberSignatures.isEmpty()}
|
||||
.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")
|
||||
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")
|
||||
}}
|
||||
|
||||
|
||||
+56
-68
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.KotlinClassMetadata
|
||||
@@ -6,33 +11,31 @@ import org.objectweb.asm.tree.*
|
||||
import kotlin.comparisons.*
|
||||
|
||||
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")
|
||||
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 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()}"
|
||||
|
||||
}
|
||||
|
||||
fun ClassVisibility.findMember(signature: MemberSignature): MemberVisibility? =
|
||||
members[signature] ?: partVisibilities.mapNotNull { it.members[signature] }.firstOrNull()
|
||||
|
||||
interface MemberBinarySignature {
|
||||
val name: String
|
||||
@@ -40,9 +43,9 @@ interface MemberBinarySignature {
|
||||
val access: AccessFlags
|
||||
val isPublishedApi: Boolean
|
||||
|
||||
fun isEffectivelyPublic(classAccess: AccessFlags, classVisibility: ClassVisibility?)
|
||||
= access.isPublic && !(access.isProtected && classAccess.isFinal)
|
||||
&& (findMemberVisibility(classVisibility)?.isPublic(isPublishedApi) ?: true)
|
||||
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(MemberSignature(name, desc))
|
||||
@@ -52,10 +55,11 @@ interface MemberBinarySignature {
|
||||
}
|
||||
|
||||
data class MethodBinarySignature(
|
||||
override val name: String,
|
||||
override val desc: String,
|
||||
override val isPublishedApi: Boolean,
|
||||
override val access: AccessFlags) : MemberBinarySignature {
|
||||
override val name: String,
|
||||
override val desc: String,
|
||||
override val isPublishedApi: Boolean,
|
||||
override val access: AccessFlags
|
||||
) : MemberBinarySignature {
|
||||
override val signature: String
|
||||
get() = "${access.getModifierString()} fun $name $desc"
|
||||
|
||||
@@ -92,35 +96,31 @@ data class MethodBinarySignature(
|
||||
}
|
||||
|
||||
data class FieldBinarySignature(
|
||||
override val name: String,
|
||||
override val desc: String,
|
||||
override val isPublishedApi: Boolean,
|
||||
override val access: AccessFlags) : MemberBinarySignature {
|
||||
override val name: String,
|
||||
override val desc: String,
|
||||
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? {
|
||||
val fieldVisibility = super.findMemberVisibility(classVisibility)
|
||||
return super.findMemberVisibility(classVisibility)
|
||||
?: takeIf { access.isStatic }?.let { super.findMemberVisibility(classVisibility?.companionVisibilities) }
|
||||
?: return null
|
||||
|
||||
if (fieldVisibility.isLateInit()) {
|
||||
classVisibility?.findSetterForProperty(fieldVisibility)?.let { return it }
|
||||
}
|
||||
return fieldVisibility
|
||||
}
|
||||
}
|
||||
|
||||
val MemberBinarySignature.kind: Int get() = when (this) {
|
||||
is FieldBinarySignature -> 1
|
||||
is MethodBinarySignature -> 2
|
||||
else -> error("Unsupported $this")
|
||||
}
|
||||
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 }
|
||||
{ it.kind },
|
||||
{ it.name },
|
||||
{ it.desc }
|
||||
)
|
||||
|
||||
|
||||
@@ -143,10 +143,10 @@ fun isSynthetic(access: Int) = access and Opcodes.ACC_SYNTHETIC != 0
|
||||
|
||||
|
||||
fun ClassNode.isEffectivelyPublic(classVisibility: ClassVisibility?) =
|
||||
isPublic(access)
|
||||
&& !isLocal()
|
||||
&& !isWhenMappings()
|
||||
&& (classVisibility?.isPublic(isPublishedApi()) ?: true)
|
||||
isPublic(access)
|
||||
&& !isLocal()
|
||||
&& !isWhenMappings()
|
||||
&& (classVisibility?.isPublic(isPublishedApi()) ?: true)
|
||||
|
||||
|
||||
val ClassNode.innerClassNode: InnerClassNode? get() = innerClasses.singleOrNull { it.name == name }
|
||||
@@ -164,21 +164,9 @@ fun MethodNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, inc
|
||||
fun FieldNode.isPublishedApi() = findAnnotation(publishedApiAnnotationName, includeInvisible = true) != null
|
||||
|
||||
|
||||
private object KotlinClassKind {
|
||||
const val FILE = 2
|
||||
const val SYNTHETIC_CLASS = 3
|
||||
const val MULTIPART_FACADE = 4
|
||||
|
||||
val FILE_OR_MULTIPART_FACADE_KINDS = listOf(FILE, MULTIPART_FACADE)
|
||||
}
|
||||
|
||||
fun ClassNode.isFileOrMultipartFacade() = kotlinClassKind.let { it != null && it in KotlinClassKind.FILE_OR_MULTIPART_FACADE_KINDS }
|
||||
fun ClassNode.isDefaultImpls(metadata: KotlinClassMetadata?) = isInner() && name.endsWith("\$DefaultImpls") && metadata.isSyntheticClass()
|
||||
|
||||
|
||||
val ClassNode.kotlinClassKind: Int?
|
||||
get() = findAnnotation("kotlin/Metadata", false)?.get("k") as Int?
|
||||
|
||||
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)
|
||||
@@ -186,15 +174,15 @@ fun FieldNode.findAnnotation(annotationName: String, includeInvisible: Boolean =
|
||||
operator fun AnnotationNode.get(key: String): Any? = values.annotationValue(key)
|
||||
|
||||
private fun List<Any>.annotationValue(key: String): Any? {
|
||||
for (index in (0 .. size / 2 - 1)) {
|
||||
if (this[index*2] == key)
|
||||
return this[index*2 + 1]
|
||||
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
|
||||
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)
|
||||
+1
@@ -12,6 +12,7 @@ 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?,
|
||||
|
||||
+11
-43
@@ -1,13 +1,19 @@
|
||||
package org.jetbrains.kotlin.tools
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
import com.google.gson.internal.Streams
|
||||
import com.google.gson.stream.JsonReader
|
||||
import java.io.File
|
||||
package org.jetbrains.kotlin.tools
|
||||
|
||||
class ClassVisibility(val name: String, val visibility: String?, val members: Map<MemberSignature, MemberVisibility>, val isCompanion: Boolean = false, val facadeClassName: String? = null) {
|
||||
var companionVisibilities: ClassVisibility? = null
|
||||
val partVisibilities = mutableListOf<ClassVisibility>()
|
||||
}
|
||||
|
||||
fun ClassVisibility.findMember(signature: MemberSignature): MemberVisibility? =
|
||||
members[signature] ?: partVisibilities.mapNotNull { it.members[signature] }.firstOrNull()
|
||||
|
||||
|
||||
data class MemberVisibility(val member: MemberSignature, val declaration: String?, val visibility: String?)
|
||||
data class MemberSignature(val name: String, val desc: String)
|
||||
|
||||
@@ -15,44 +21,6 @@ private fun isPublic(visibility: String?, isPublishedApi: Boolean) = visibility
|
||||
fun ClassVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi)
|
||||
fun MemberVisibility.isPublic(isPublishedApi: Boolean) = isPublic(visibility, isPublishedApi)
|
||||
|
||||
fun MemberVisibility.isLateInit() = declaration != null && "lateinit var " in declaration
|
||||
|
||||
private val varValPrefix = Regex("va[lr]\\s+")
|
||||
fun ClassVisibility.findSetterForProperty(property: MemberVisibility): MemberVisibility? {
|
||||
// ad-hoc solution:
|
||||
val declaration = property.declaration ?: return null
|
||||
val match = varValPrefix.find(declaration) ?: return null
|
||||
val name = declaration.substring(match.range.endInclusive + 1).substringBefore(':')
|
||||
val setterName = "<set-$name>"
|
||||
return members.values.find { it.declaration?.contains(setterName) ?: false }
|
||||
}
|
||||
|
||||
fun readKotlinVisibilities(declarationFile: File): Map<String, ClassVisibility> {
|
||||
val result = mutableListOf<ClassVisibility>()
|
||||
declarationFile.bufferedReader().use { reader ->
|
||||
val jsonReader = JsonReader(reader)
|
||||
jsonReader.beginArray()
|
||||
while (jsonReader.hasNext()) {
|
||||
val classObject = Streams.parse(jsonReader).asJsonObject
|
||||
result += with (classObject) {
|
||||
val name = getAsJsonPrimitive("class").asString
|
||||
val visibility = getAsJsonPrimitive("visibility")?.asString
|
||||
val members = getAsJsonArray("members").map { it ->
|
||||
with(it.asJsonObject) {
|
||||
val name = getAsJsonPrimitive("name").asString
|
||||
val desc = getAsJsonPrimitive("desc").asString
|
||||
val declaration = getAsJsonPrimitive("declaration")?.asString
|
||||
val visibility = getAsJsonPrimitive("visibility")?.asString
|
||||
MemberVisibility(MemberSignature(name, desc), declaration, visibility)
|
||||
}
|
||||
}
|
||||
ClassVisibility(name, visibility, members.associateByTo(hashMapOf()) { it.member })
|
||||
}
|
||||
}
|
||||
jsonReader.endArray()
|
||||
}
|
||||
|
||||
return result.associateByTo(hashMapOf()) { it.name }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+10
-6
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.tests
|
||||
|
||||
import org.jetbrains.kotlin.tools.*
|
||||
@@ -8,12 +13,11 @@ import java.io.File
|
||||
class CasesPublicAPITest {
|
||||
|
||||
companion object {
|
||||
val visibilities by lazy { readKotlinVisibilities(File(System.getProperty("testCasesDeclarations")!!)) }
|
||||
val baseClassPaths: List<File> =
|
||||
System.getProperty("testCasesClassesDirs")
|
||||
.let { requireNotNull(it) { "Specify testCasesClassesDirs with a system property"} }
|
||||
.split(File.pathSeparator)
|
||||
.map { File(it, "cases").canonicalFile }
|
||||
System.getProperty("testCasesClassesDirs")
|
||||
.let { requireNotNull(it) { "Specify testCasesClassesDirs with a system property"} }
|
||||
.split(File.pathSeparator)
|
||||
.map { File(it, "cases").canonicalFile }
|
||||
val baseOutputPath = File("src/test/kotlin/cases")
|
||||
}
|
||||
|
||||
@@ -54,7 +58,7 @@ class CasesPublicAPITest {
|
||||
|
||||
val testClassStreams = testClasses.asSequence().filter { it.name.endsWith(".class") }.map { it.inputStream() }
|
||||
|
||||
val api = getBinaryAPI(testClassStreams, visibilities).filterOutNonPublic()
|
||||
val api = getBinaryAPI(testClassStreams).filterOutNonPublic()
|
||||
|
||||
val target = baseOutputPath.resolve(testClassRelativePath).resolve(testName.methodName + ".txt")
|
||||
|
||||
|
||||
+19
-35
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.tests
|
||||
@@ -29,56 +18,51 @@ class RuntimePublicAPITest {
|
||||
val testName = TestName()
|
||||
|
||||
@Test fun kotlinRuntime() {
|
||||
snapshotAPIAndCompare("../../stdlib/runtime/build/libs", "kotlin-runtime", listOf("../runtime-declarations.json"), listOf("kotlin.jvm.internal"))
|
||||
snapshotAPIAndCompare("../../stdlib/runtime/build/libs", "kotlin-runtime", listOf("kotlin.jvm.internal"))
|
||||
}
|
||||
|
||||
@Test fun kotlinStdlibRuntimeMerged() {
|
||||
snapshotAPIAndCompare(
|
||||
"../../stdlib/jvm/build/libs", "kotlin-stdlib",
|
||||
listOf("../stdlib-declarations.json"/*, "../stdlib-experimental-declarations.json"*/),
|
||||
listOf("kotlin.jvm.internal")
|
||||
)
|
||||
snapshotAPIAndCompare("../../stdlib/jvm/build/libs", "kotlin-stdlib", listOf("kotlin.jvm.internal"))
|
||||
}
|
||||
|
||||
@Test fun kotlinStdlibJdk7() {
|
||||
snapshotAPIAndCompare("../../stdlib/jdk7/build/libs", "kotlin-stdlib-jdk7", listOf("../stdlib-jdk7-declarations.json"))
|
||||
snapshotAPIAndCompare("../../stdlib/jdk7/build/libs", "kotlin-stdlib-jdk7")
|
||||
}
|
||||
|
||||
@Test fun kotlinStdlibJdk8() {
|
||||
snapshotAPIAndCompare("../../stdlib/jdk8/build/libs", "kotlin-stdlib-jdk8", listOf("../stdlib-jdk8-declarations.json"))
|
||||
snapshotAPIAndCompare("../../stdlib/jdk8/build/libs", "kotlin-stdlib-jdk8")
|
||||
}
|
||||
|
||||
@Test fun kotlinStdlibJre7() {
|
||||
snapshotAPIAndCompare("../../stdlib/jre7/build/libs", "kotlin-stdlib-jre7", listOf("../stdlib-jre7-declarations.json"))
|
||||
snapshotAPIAndCompare("../../stdlib/jre7/build/libs", "kotlin-stdlib-jre7")
|
||||
}
|
||||
|
||||
@Test fun kotlinStdlibJre8() {
|
||||
snapshotAPIAndCompare("../../stdlib/jre8/build/libs", "kotlin-stdlib-jre8", listOf("../stdlib-jre8-declarations.json"))
|
||||
snapshotAPIAndCompare("../../stdlib/jre8/build/libs", "kotlin-stdlib-jre8")
|
||||
}
|
||||
|
||||
@Test fun kotlinReflect() {
|
||||
snapshotAPIAndCompare("../../reflect/api/build/libs", "kotlin-reflect-api(?!-[-a-z]+)", listOf("../reflect-declarations.json"), nonPublicPackages = listOf("kotlin.reflect.jvm.internal"))
|
||||
snapshotAPIAndCompare("../../reflect/api/build/libs", "kotlin-reflect-api(?!-[-a-z]+)", nonPublicPackages = listOf("kotlin.reflect.jvm.internal"))
|
||||
}
|
||||
|
||||
|
||||
private fun snapshotAPIAndCompare(basePath: String, jarPattern: String, kotlinJvmMappingsPath: List<String>, publicPackages: List<String> = emptyList(), nonPublicPackages: List<String> = emptyList()) {
|
||||
private fun snapshotAPIAndCompare(
|
||||
basePath: String,
|
||||
jarPattern: String,
|
||||
publicPackages: List<String> = emptyList(),
|
||||
nonPublicPackages: List<String> = emptyList()
|
||||
) {
|
||||
val base = File(basePath).absoluteFile.normalize()
|
||||
val jarFile = getJarPath(base, jarPattern, System.getProperty("kotlinVersion"))
|
||||
val kotlinJvmMappingsFiles = kotlinJvmMappingsPath.map(base::resolve)
|
||||
|
||||
println("Reading kotlin visibilities from $kotlinJvmMappingsFiles")
|
||||
val publicPackagePrefixes = publicPackages.map { it.replace('.', '/') + '/' }
|
||||
val publicPackageFilter = { className: String -> publicPackagePrefixes.none { className.startsWith(it) } }
|
||||
val visibilities =
|
||||
kotlinJvmMappingsFiles
|
||||
.map { readKotlinVisibilities(it).filterKeys(publicPackageFilter) }
|
||||
.reduce { m1, m2 -> m1 + m2 }
|
||||
|
||||
println("Reading binary API from $jarFile")
|
||||
val api = getBinaryAPI(JarFile(jarFile), visibilities, publicPackageFilter).filterOutNonPublic(nonPublicPackages)
|
||||
val api = getBinaryAPI(JarFile(jarFile), publicPackageFilter).filterOutNonPublic(nonPublicPackages)
|
||||
|
||||
val target = File("reference-public-api")
|
||||
.resolve(testName.methodName.replaceCamelCaseWithDashedLowerCase() + ".txt")
|
||||
.resolve(testName.methodName.replaceCamelCaseWithDashedLowerCase() + ".txt")
|
||||
|
||||
api.dumpAndCompareWith(target)
|
||||
}
|
||||
@@ -89,8 +73,8 @@ class RuntimePublicAPITest {
|
||||
val files = (base.listFiles() ?: throw Exception("Cannot list files in $base"))
|
||||
.filter { it.name.let {
|
||||
it matches regex
|
||||
&& !it.endsWith("-sources.jar")
|
||||
&& !it.endsWith("-javadoc.jar") } }
|
||||
&& !it.endsWith("-sources.jar")
|
||||
&& !it.endsWith("-javadoc.jar") } }
|
||||
|
||||
return files.singleOrNull() ?: throw Exception("No single file matching $regex in $base:\n${files.joinToString("\n")}")
|
||||
}
|
||||
|
||||
+5
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.tests
|
||||
|
||||
import org.jetbrains.kotlin.tools.*
|
||||
|
||||
Reference in New Issue
Block a user