Check descriptor visibility before excluding method from ABI class
This commit is contained in:
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.jvm.abi.asm
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
|
||||
@@ -22,10 +24,15 @@ internal class AbiClassBuilder(private val cv: ClassVisitor) : AbstractClassBuil
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
if (isPrivate(access) || isClinit(name, access)) return EMPTY_METHOD_VISITOR
|
||||
// if both descriptor's and access's visibilities are private, we can generate an empty method
|
||||
// 1. we need to check a descriptor, because inline reified functions
|
||||
// might have a non-private visibility in ABI, but they are private in bytecode
|
||||
// 2. we need to check an access, because synthetic methods
|
||||
// for default parameters have private visibility, but public in bytecode
|
||||
val descriptor = origin.descriptor as? MemberDescriptor
|
||||
if (isPrivate(access) && descriptor != null && isPrivate(descriptor) || isClinit(name, access)) return EMPTY_METHOD_VISITOR
|
||||
|
||||
val mv = super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
val descriptor = origin.descriptor
|
||||
// inline function bodies are part of ABI,
|
||||
// but non-inline functions can be thrown out
|
||||
if (descriptor is FunctionDescriptor && descriptor.isInline) return mv
|
||||
@@ -67,6 +74,9 @@ internal class AbiClassBuilder(private val cv: ClassVisitor) : AbstractClassBuil
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
private fun isPrivate(descriptor: MemberDescriptor): Boolean =
|
||||
descriptor.visibility == Visibilities.PRIVATE
|
||||
|
||||
private fun isPrivate(access: Int): Boolean =
|
||||
(access and Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE
|
||||
|
||||
|
||||
Generated
+5
@@ -44,6 +44,11 @@ public class CompileAgainstJvmAbiTestGenerated extends AbstractCompileAgainstJvm
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/clinit/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineReifiedFunction")
|
||||
public void testInlineReifiedFunction() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("privateOnlyConstructors")
|
||||
public void testPrivateOnlyConstructors() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package app
|
||||
|
||||
import lib.*
|
||||
|
||||
fun runAppAndReturnOk(): String {
|
||||
val a = safeCall<Int>(10) { it * it }
|
||||
if (a != 100) error("a is '$a', but is expected to be '100'")
|
||||
|
||||
val b = safeCall<Int>(null) { it * it }
|
||||
if (b != null) error("b is '$b', but is expected to be 'null'")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package lib
|
||||
|
||||
inline fun <reified T> safeCall(x: Any?, fn: (T) -> T): T? =
|
||||
if (x is T) fn(x) else null
|
||||
Reference in New Issue
Block a user