-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ABI Validation] bcv: use kotlinx-metadata-jvm to read kotlin visibil…
…ities It's no longer required to dump kotlin-to-java declaration mapping to json before using binary-compatibility-validator. @jvmoverloads are not supported yet, so remove them from test. Use asm:6.0 in bcv Moved from Kotlin/binary-compatibility-validator@502d73c
- Loading branch information
1 parent
c706574
commit 2f84a22
Showing
6 changed files
with
293 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
198 changes: 198 additions & 0 deletions
198
...s/abi-validation/src/main/kotlin/org.jetbrains.kotlin.tools/kotlinMetadataVisibilities.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* | ||
* 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.* | ||
import kotlinx.metadata.jvm.* | ||
import org.objectweb.asm.tree.ClassNode | ||
|
||
val ClassNode.kotlinMetadata: KotlinClassMetadata? | ||
get() { | ||
val metadata = findAnnotation("kotlin/Metadata", false) ?: return null | ||
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 | ||
|
||
|
||
private val VISIBILITY_FLAGS_MAP = mapOf( | ||
Flag.IS_INTERNAL to "internal", | ||
Flag.IS_PRIVATE to "private", | ||
Flag.IS_PRIVATE_TO_THIS to "private", | ||
Flag.IS_PROTECTED to "protected", | ||
Flag.IS_PUBLIC to "public", | ||
Flag.IS_LOCAL to "local" | ||
) | ||
|
||
private fun Flags.toVisibility() = VISIBILITY_FLAGS_MAP.entries.firstOrNull { (modifier) -> modifier(this) }?.value | ||
private fun String.toMemberSignature() = indexOf("(").let { i -> | ||
if (i < 0) MemberSignature("", this) else MemberSignature(substring(0, i), substring(i)) | ||
} | ||
|
||
private fun visitFunction(flags: Flags, name: String, addMember: (MemberVisibility) -> Unit) = | ||
object : KmFunctionVisitor() { | ||
var jvmDesc: String? = null | ||
override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? { | ||
if (type != JvmFunctionExtensionVisitor.TYPE) return null | ||
return object : JvmFunctionExtensionVisitor() { | ||
override fun visit(desc: String?) { | ||
jvmDesc = desc | ||
} | ||
} | ||
} | ||
|
||
override fun visitEnd() { | ||
jvmDesc?.let { jvmDesc -> | ||
addMember(MemberVisibility(jvmDesc.toMemberSignature(), name, flags.toVisibility())) | ||
} | ||
} | ||
} | ||
|
||
private fun visitConstructor(flags: Flags, addMember: (MemberVisibility) -> Unit) = | ||
object : KmConstructorVisitor() { | ||
var jvmDesc: String? = null | ||
override fun visitExtensions(type: KmExtensionType): KmConstructorExtensionVisitor? { | ||
if (type != JvmConstructorExtensionVisitor.TYPE) return null | ||
return object : JvmConstructorExtensionVisitor() { | ||
override fun visit(desc: String?) { | ||
jvmDesc = desc | ||
} | ||
} | ||
} | ||
|
||
override fun visitEnd() { | ||
jvmDesc?.toMemberSignature()?.let { signature -> | ||
addMember(MemberVisibility(signature, signature.name, flags.toVisibility())) | ||
} | ||
} | ||
} | ||
|
||
private fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags, addMember: (MemberVisibility) -> Unit) = | ||
object : KmPropertyVisitor() { | ||
var fieldDesc: MemberSignature? = null | ||
var _getterDesc: MemberSignature? = null | ||
var _setterDesc: MemberSignature? = null | ||
|
||
override fun visitExtensions(type: KmExtensionType): KmPropertyExtensionVisitor? { | ||
if (type != JvmPropertyExtensionVisitor.TYPE) return null | ||
return object : JvmPropertyExtensionVisitor() { | ||
override fun visit(fieldName: String?, fieldTypeDesc: String?, getterDesc: String?, setterDesc: String?) { | ||
if (fieldName != null && fieldTypeDesc != null) | ||
fieldDesc = MemberSignature(fieldName, fieldTypeDesc) | ||
|
||
_getterDesc = getterDesc?.toMemberSignature() | ||
_setterDesc = setterDesc?.toMemberSignature() | ||
} | ||
} | ||
} | ||
|
||
override fun visitEnd() { | ||
_getterDesc?.let { addMember(MemberVisibility(it, name, getterFlags.toVisibility())) } | ||
_setterDesc?.let { addMember(MemberVisibility(it, name, setterFlags.toVisibility())) } | ||
fieldDesc?.let { | ||
val fieldVisibility = (when { | ||
Flag.Property.IS_LATEINIT(flags) -> setterFlags | ||
_getterDesc == null && _setterDesc == null -> flags // JvmField or const case | ||
else -> flagsOf(Flag.IS_PRIVATE) | ||
}).toVisibility() | ||
addMember(MemberVisibility(it, name, fieldVisibility)) | ||
} | ||
} | ||
} | ||
|
||
private fun visitPackage(addMember: (MemberVisibility) -> Unit) = | ||
object : KmPackageVisitor() { | ||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? { | ||
return visitFunction(flags, name, addMember) | ||
} | ||
|
||
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? { | ||
return visitProperty(flags, name, getterFlags, setterFlags, addMember) | ||
} | ||
|
||
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? { | ||
return super.visitTypeAlias(flags, name) | ||
} | ||
} | ||
|
||
private fun visitClass(flags: (Flags) -> Unit, addMember: (MemberVisibility) -> Unit) = | ||
object : KmClassVisitor() { | ||
override fun visit(flags: Flags, name: ClassName) { | ||
flags(flags) | ||
} | ||
|
||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? { | ||
return visitFunction(flags, name, addMember) | ||
} | ||
|
||
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? { | ||
return visitProperty(flags, name, getterFlags, setterFlags, addMember) | ||
} | ||
|
||
override fun visitConstructor(flags: Flags): KmConstructorVisitor? { | ||
return visitConstructor(flags, addMember) | ||
} | ||
|
||
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? { | ||
return super.visitTypeAlias(flags, name) | ||
} | ||
} | ||
|
||
fun KotlinClassMetadata.toClassVisibility(classNode: ClassNode): ClassVisibility? { | ||
var flags: Flags? = null | ||
var _facadeClassName: String? = null | ||
val members = mutableListOf<MemberVisibility>() | ||
val addMember: (MemberVisibility) -> Unit = { members.add(it) } | ||
|
||
when (this) { | ||
is KotlinClassMetadata.Class -> | ||
this.accept(visitClass({ flags = it }, addMember)) | ||
is KotlinClassMetadata.FileFacade -> | ||
this.accept(visitPackage(addMember)) | ||
is KotlinClassMetadata.MultiFileClassPart -> { | ||
_facadeClassName = this.facadeClassName | ||
this.accept(visitPackage(addMember)) | ||
} | ||
else -> {} | ||
} | ||
return ClassVisibility(classNode.name, | ||
flags?.toVisibility(), | ||
members.associateBy { it.member }, | ||
flags?.let { Flag.Class.IS_COMPANION_OBJECT(it) } ?: false, | ||
_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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.