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 index e583f6b048d..5c037067343 100644 --- 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 @@ -32,23 +32,23 @@ fun ClassNode.isEffectivelyPublic(classVisibility: ClassVisibility?) = isPublic() && !isLocal() && !isWhenMappings() - && (classVisibility?.isPublic() ?: true) + && (classVisibility?.isPublic(isInlineExposed()) ?: true) && !isNonPublicFileOrFacade(classVisibility) fun ClassNode.isNonPublicFileOrFacade(classVisibility: ClassVisibility?) = isFileOrMultipartFacade() && methods.none { it.isEffectivelyPublic(classVisibility) } - && fields.none { it.isPublic() } + && fields.none { it.isEffectivelyPublic(classVisibility) } fun MethodNode.isEffectivelyPublic(classVisibility: ClassVisibility?) = isPublic() - && (classVisibility?.members?.get(MemberSignature(name, desc))?.isPublic() ?: true) + && (classVisibility?.members?.get(MemberSignature(name, desc))?.isPublic(isInlineExposed()) ?: true) && !isAccessMethod() fun FieldNode.isEffectivelyPublic(classVisibility: ClassVisibility?) = isPublic() - && (classVisibility?.members?.get(MemberSignature(name, desc))?.isPublic() ?: true) + && (classVisibility?.members?.get(MemberSignature(name, desc))?.isPublic(isInlineExposed()) ?: true) // TODO: lateinit exposed field @@ -58,6 +58,10 @@ fun MethodNode.isAccessMethod() = isSynthetic() && name.startsWith("access\$") val ClassNode.effectiveAccess: Int get() = innerClasses.singleOrNull { it.name == name }?.access ?: access +const val inlineExposedAnnotationName = "kotlin/internal/InlineExposed" +fun ClassNode.isInlineExposed() = hasAnnotation(inlineExposedAnnotationName, includeInvisible = true) +fun MethodNode.isInlineExposed() = hasAnnotation(inlineExposedAnnotationName, includeInvisible = true) +fun FieldNode.isInlineExposed() = hasAnnotation(inlineExposedAnnotationName, includeInvisible = true) private object KotlinClassKind { const val FILE = 2 @@ -75,8 +79,15 @@ val ClassNode.kotlinClassKind: Int? ?.map { (it.values.annotationValue("k") as? Int) } ?.firstOrNull() -fun ClassNode.hasAnnotation(annotationName: String) - = "L$annotationName;".let { desc -> visibleAnnotations?.any { it.desc == desc } ?: false } +fun ClassNode.hasAnnotation(annotationName: String, includeInvisible: Boolean = false) = hasAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) +fun MethodNode.hasAnnotation(annotationName: String, includeInvisible: Boolean = false) = hasAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) +fun FieldNode.hasAnnotation(annotationName: String, includeInvisible: Boolean = false) = hasAnnotation(annotationName, visibleAnnotations, invisibleAnnotations, includeInvisible) + +private fun hasAnnotation(annotationName: String, visibleAnnotations: List?, invisibleAnnotations: List?, includeInvisible: Boolean) + = "L$annotationName;".let { desc -> + (visibleAnnotations?.any { it.desc == desc } ?: false) + || (includeInvisible && (invisibleAnnotations?.any { it.desc == desc } ?: false)) + } private fun List.annotationValue(key: String): Any? { for (index in (0 .. size / 2 - 1)) { 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 index f2f7c58231c..1f0b2dc2b60 100644 --- 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 @@ -8,9 +8,9 @@ data class ClassVisibility(val name: String, val visibility: String?, val member data class MemberVisibility(val member: MemberSignature, val visibility: String?) data class MemberSignature(val name: String, val desc: String) -private fun isPublic(visibility: String?) = visibility == null || visibility == "public" || visibility == "protected" -fun ClassVisibility.isPublic() = isPublic(visibility) -fun MemberVisibility.isPublic() = isPublic(visibility) +private fun isPublic(visibility: String?, isInlineExposed: Boolean) = visibility == null || visibility == "public" || visibility == "protected" || (isInlineExposed && visibility == "internal") +fun ClassVisibility.isPublic(isInlineExposed: Boolean) = isPublic(visibility, isInlineExposed) +fun MemberVisibility.isPublic(isInlineExposed: Boolean) = isPublic(visibility, isInlineExposed) fun readKotlinVisibilities(declarationFile: File): Map { diff --git a/libraries/tools/binary-compatibility-validator/src/test/kotlin/cases/inline/inlineExposed.kt b/libraries/tools/binary-compatibility-validator/src/test/kotlin/cases/inline/inlineExposed.kt index c1bd1935927..08f4f2b1e8c 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/kotlin/cases/inline/inlineExposed.kt +++ b/libraries/tools/binary-compatibility-validator/src/test/kotlin/cases/inline/inlineExposed.kt @@ -12,11 +12,14 @@ internal class InternalClassExposed @kotlin.internal.InlineExposed internal fun funExposed() {} + // TODO: Cover unsupported cases: requires correctly reflecting annotations from properties + /* @kotlin.internal.InlineExposed internal var propertyExposed: String? = null @JvmField @kotlin.internal.InlineExposed internal var fieldExposed: String? = null + */ } diff --git a/libraries/tools/binary-compatibility-validator/src/test/resources/output/cases/inline.txt b/libraries/tools/binary-compatibility-validator/src/test/resources/output/cases/inline.txt index e69de29bb2d..25e6c746553 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/resources/output/cases/inline.txt +++ b/libraries/tools/binary-compatibility-validator/src/test/resources/output/cases/inline.txt @@ -0,0 +1,9 @@ +public final class cases/inline/InlineExposedKt +public static final fun exposedForInline ()V +------------------ + +public final class cases/inline/InternalClassExposed +public fun ()V +public final fun funExposed$binary_compatibility_validator ()V +------------------ + diff --git a/libraries/tools/binary-compatibility-validator/src/test/resources/output/kotlin-stdlib.txt b/libraries/tools/binary-compatibility-validator/src/test/resources/output/kotlin-stdlib.txt index c572d68d39e..a132288eade 100644 --- a/libraries/tools/binary-compatibility-validator/src/test/resources/output/kotlin-stdlib.txt +++ b/libraries/tools/binary-compatibility-validator/src/test/resources/output/kotlin-stdlib.txt @@ -62,6 +62,10 @@ public static final fun toList (Lkotlin/Pair;)Ljava/util/List; public static final fun toList (Lkotlin/Triple;)Ljava/util/List; ------------------ +public final class kotlin/_Assertions +public static final field INSTANCE Lkotlin/_Assertions; +------------------ + public abstract class kotlin/collections/AbstractIterator: java/util/Iterator, kotlin/jvm/internal/markers/KMappedMarker public fun ()V protected abstract fun computeNext ()V @@ -1286,6 +1290,8 @@ public static synthetic fun binarySearch$default (Ljava/util/List;Ljava/lang/Com public static synthetic fun binarySearch$default (Ljava/util/List;Ljava/lang/Object;Ljava/util/Comparator;IIILjava/lang/Object;)I public static final fun binarySearchBy (Ljava/util/List;Ljava/lang/Comparable;IILkotlin/jvm/functions/Function1;)I public static synthetic fun binarySearchBy$default (Ljava/util/List;Ljava/lang/Comparable;IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I +public static final fun collectionSizeOrDefault (Ljava/lang/Iterable;I)I +public static final fun collectionSizeOrNull (Ljava/lang/Iterable;)Ljava/lang/Integer; public static final fun contains (Ljava/lang/Iterable;Ljava/lang/Object;)Z public static final fun count (Ljava/lang/Iterable;)I public static final fun count (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)I @@ -1493,11 +1499,13 @@ public static final fun filterValues (Ljava/util/Map;Lkotlin/jvm/functions/Funct public static final fun flatMap (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/List; public static final fun flatMapTo (Ljava/util/Map;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;)Ljava/util/Collection; public static final fun forEach (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)V +public static final fun getOrImplicitDefaultNullable (Ljava/util/Map;Ljava/lang/Object;)Ljava/lang/Object; public static final fun getOrPut (Ljava/util/Map;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun getOrPut (Ljava/util/concurrent/ConcurrentMap;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun hashMapOf ([Lkotlin/Pair;)Ljava/util/HashMap; public static final fun linkedMapOf ([Lkotlin/Pair;)Ljava/util/LinkedHashMap; public static final fun map (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/List; +public static final fun mapCapacity (I)I public static final fun mapKeys (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun mapKeysTo (Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map; public static final fun mapNotNull (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/List; @@ -1571,6 +1579,10 @@ public static final fun thread (ZZLjava/lang/ClassLoader;Ljava/lang/String;ILkot public static synthetic fun thread$default (ZZLjava/lang/ClassLoader;Ljava/lang/String;ILkotlin/jvm/functions/Function0;ILjava/lang/Object;)Ljava/lang/Thread; ------------------ +public final class kotlin/concurrent/TimersKt +public static final fun timer (Ljava/lang/String;Z)Ljava/util/Timer; +------------------ + public final class kotlin/io/AccessDeniedException: kotlin/io/FileSystemException public fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;)V public synthetic fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -1693,6 +1705,11 @@ public static final fun readText (Ljava/io/Reader;)Ljava/lang/String; public static final fun useLines (Ljava/io/Reader;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; ------------------ +public final class kotlin/jvm/internal/unsafe/MonitorKt +public static final fun monitorEnter (Ljava/lang/Object;)V +public static final fun monitorExit (Ljava/lang/Object;)V +------------------ + public final class kotlin/properties/Delegates public static final field INSTANCE Lkotlin/properties/Delegates; public final fun notNull ()Lkotlin/properties/ReadWriteProperty; @@ -2104,6 +2121,7 @@ public static final field Companion Lkotlin/text/Regex$Companion; public fun (Ljava/lang/String;)V public fun (Ljava/lang/String;Ljava/util/Set;)V public fun (Ljava/lang/String;Lkotlin/text/RegexOption;)V +public fun (Ljava/util/regex/Pattern;)V public final fun containsMatchIn (Ljava/lang/CharSequence;)Z public final fun find (Ljava/lang/CharSequence;I)Lkotlin/text/MatchResult; public static synthetic fun find$default (Lkotlin/text/Regex;Ljava/lang/CharSequence;IILjava/lang/Object;)Lkotlin/text/MatchResult;