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 com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
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.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
|
|
||||||
@@ -22,10 +24,15 @@ internal class AbiClassBuilder(private val cv: ClassVisitor) : AbstractClassBuil
|
|||||||
signature: String?,
|
signature: String?,
|
||||||
exceptions: Array<out String>?
|
exceptions: Array<out String>?
|
||||||
): MethodVisitor {
|
): 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 mv = super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||||
val descriptor = origin.descriptor
|
|
||||||
// inline function bodies are part of ABI,
|
// inline function bodies are part of ABI,
|
||||||
// but non-inline functions can be thrown out
|
// but non-inline functions can be thrown out
|
||||||
if (descriptor is FunctionDescriptor && descriptor.isInline) return mv
|
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)
|
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 =
|
private fun isPrivate(access: Int): Boolean =
|
||||||
(access and Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE
|
(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/");
|
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")
|
@TestMetadata("privateOnlyConstructors")
|
||||||
public void testPrivateOnlyConstructors() throws Exception {
|
public void testPrivateOnlyConstructors() throws Exception {
|
||||||
runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/");
|
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