jvm-abi-gen: Mark all anonymous objects in inline function scope as public

Anonymous objects inside of a private inline function nested in a public
inline function can still escape.
This commit is contained in:
Steven Schäfer
2021-06-29 16:43:45 +02:00
committed by Alexander Udalov
parent d94817cfb6
commit 3ffe495346
11 changed files with 115 additions and 15 deletions
@@ -418,9 +418,20 @@ class PsiSourceCompilerForInline(
fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean = fun DeclarationDescriptor.isInlineOrInsideInline(): Boolean =
getInlineCallSiteVisibility() != null getInlineCallSiteVisibility() != null
fun DeclarationDescriptor.getInlineCallSiteVisibility(): DescriptorVisibility? = fun DeclarationDescriptor.getInlineCallSiteVisibility(): DescriptorVisibility? {
if (this is FunctionDescriptor && isInline) visibility var declaration: DeclarationDescriptor? = this
else containingDeclaration?.getInlineCallSiteVisibility() var result: DescriptorVisibility? = null
while (declaration != null) {
if (declaration is FunctionDescriptor && declaration.isInline) {
if (!DescriptorVisibilities.isPrivate(declaration.visibility)) {
return declaration.visibility
}
result = declaration.visibility
}
declaration = declaration.containingDeclaration
}
return result
}
fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> { fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set<String> {
val result = HashSet<String>() val result = HashSet<String>()
@@ -76,11 +76,10 @@ public class InlineUtil {
public static boolean isInPublicInlineScope(@Nullable DeclarationDescriptor descriptor) { public static boolean isInPublicInlineScope(@Nullable DeclarationDescriptor descriptor) {
if (descriptor == null) return false; if (descriptor == null) return false;
if (isInline(descriptor)) { if (isInline(descriptor) && descriptor instanceof DeclarationDescriptorWithVisibility) {
if (!(descriptor instanceof DeclarationDescriptorWithVisibility))
return false;
DescriptorVisibility visibility = ((DeclarationDescriptorWithVisibility) descriptor).getVisibility(); DescriptorVisibility visibility = ((DeclarationDescriptorWithVisibility) descriptor).getVisibility();
return !DescriptorVisibilities.isPrivate(visibility); if (!DescriptorVisibilities.isPrivate(visibility))
return true;
} }
return isInPublicInlineScope(descriptor.getContainingDeclaration()); return isInPublicInlineScope(descriptor.getContainingDeclaration());
} }
@@ -13,10 +13,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.representativeUpperBound
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.config.JvmDefaultMode import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -431,13 +428,17 @@ private val IrDeclaration.original: IrDeclaration
// (determined *before* lowering), or null if the given declaration is not in the scope of an inline function. // (determined *before* lowering), or null if the given declaration is not in the scope of an inline function.
val IrDeclaration.inlineScopeVisibility: DescriptorVisibility? val IrDeclaration.inlineScopeVisibility: DescriptorVisibility?
get() { get() {
var owner = original var owner: IrDeclaration? = original
while (true) { var result: DescriptorVisibility? = null
while (owner != null) {
if (owner is IrFunction && owner.isInline) { if (owner is IrFunction && owner.isInline) {
return owner.visibility if (!DescriptorVisibilities.isPrivate(owner.visibility))
return owner.visibility
result = owner.visibility
} }
owner = owner.parent.safeAs<IrDeclaration>()?.original ?: return null owner = owner.parent.safeAs<IrDeclaration>()?.original
} }
return result
} }
// True for declarations which are in the scope of an externally visible inline function. // True for declarations which are in the scope of an externally visible inline function.
@@ -55,11 +55,21 @@ public class CompileAgainstJvmAbiTestGenerated extends AbstractCompileAgainstJvm
runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/");
} }
@TestMetadata("inlineNoRegeneration")
public void testInlineNoRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineNoRegeneration/");
}
@TestMetadata("inlineReifiedFunction") @TestMetadata("inlineReifiedFunction")
public void testInlineReifiedFunction() throws Exception { public void testInlineReifiedFunction() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
} }
@TestMetadata("innerObjectRegeneration")
public void testInnerObjectRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/innerObjectRegeneration/");
}
@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/");
@@ -55,11 +55,21 @@ public class IrCompileAgainstJvmAbiTestGenerated extends AbstractIrCompileAgains
runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/");
} }
@TestMetadata("inlineNoRegeneration")
public void testInlineNoRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineNoRegeneration/");
}
@TestMetadata("inlineReifiedFunction") @TestMetadata("inlineReifiedFunction")
public void testInlineReifiedFunction() throws Exception { public void testInlineReifiedFunction() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
} }
@TestMetadata("innerObjectRegeneration")
public void testInnerObjectRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/innerObjectRegeneration/");
}
@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/");
@@ -55,11 +55,21 @@ public class LegacyCompileAgainstJvmAbiTestGenerated extends AbstractLegacyCompi
runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/");
} }
@TestMetadata("inlineNoRegeneration")
public void testInlineNoRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineNoRegeneration/");
}
@TestMetadata("inlineReifiedFunction") @TestMetadata("inlineReifiedFunction")
public void testInlineReifiedFunction() throws Exception { public void testInlineReifiedFunction() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/"); runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
} }
@TestMetadata("innerObjectRegeneration")
public void testInnerObjectRegeneration() throws Exception {
runTest("plugins/jvm-abi-gen/testData/compile/innerObjectRegeneration/");
}
@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,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"K"
}
return result
}
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
result = object { //should be marked as public abi as there is no regenerated abject on inline
fun run(): String {
return "O"
}
}.run() + z()
}
fun foo() {
test { s() }
}
}.foo()
}
@@ -0,0 +1,10 @@
package app
import lib.*
fun runAppAndReturnOk(): String {
foo {
"OK"
}
return result
}
@@ -0,0 +1 @@
// IGNORE_BACKEND_LEGACY: JVM
@@ -0,0 +1,19 @@
package lib
var result = "fail"
inline fun foo(crossinline s: () -> String) {
object {
private inline fun test(crossinline z: () -> String) {
object {
fun run() {
result = z()
}
}.run()
}
fun foo() {
test { s() } // regenerated object should be marked as public abi
}
}.foo()
}