diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 3ec9818841e..e2ffedd375f 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -23490,6 +23490,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/jvmStatic/companionObject.kt"); } + @Test + @TestMetadata("companionObjectProtected.kt") + public void testCompanionObjectProtected() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt"); + } + @Test @TestMetadata("convention.kt") public void testConvention() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt index 8058b1f6813..4d6dbf14592 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt @@ -5,9 +5,8 @@ package org.jetbrains.kotlin.backend.jvm -import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom -import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor -import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers +import org.jetbrains.kotlin.backend.common.ir.* +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.jvm.codegen.AnnotationCodegen.Companion.annotationClass import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom @@ -19,11 +18,10 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildFun -import org.jetbrains.kotlin.ir.builders.irCall -import org.jetbrains.kotlin.ir.builders.setSourceRange import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities @@ -39,6 +37,7 @@ class JvmCachedDeclarations( private val singletonFieldDeclarations = ConcurrentHashMap() private val interfaceCompanionFieldDeclarations = ConcurrentHashMap() private val staticBackingFields = ConcurrentHashMap() + private val staticCompanionDeclarations = ConcurrentHashMap>() private val defaultImplsMethods = ConcurrentHashMap() private val defaultImplsClasses = ConcurrentHashMap() @@ -143,6 +142,71 @@ class JvmCachedDeclarations( } } + fun getStaticAndCompanionDeclaration(jvmStaticFunction: IrSimpleFunction): Pair = + staticCompanionDeclarations.getOrPut(jvmStaticFunction) { + val companion = jvmStaticFunction.parentAsClass + assert(companion.isCompanion) + if (jvmStaticFunction.isExternal) { + // We move external functions to the enclosing class and potentially add accessors there. + // The JVM backend also adds accessors in the companion object, but these are superfluous. + // TODO: this should really do the same as `makeProxy`, but without a body; otherwise, external + // functions in interface companions won't work (KT-43696). + val staticExternal = context.irFactory.buildFun { + updateFrom(jvmStaticFunction) + name = jvmStaticFunction.name + returnType = jvmStaticFunction.returnType + }.apply { + parent = companion.parent + copyTypeParametersFrom(jvmStaticFunction) + copyAnnotationsFrom(jvmStaticFunction) + extensionReceiverParameter = jvmStaticFunction.extensionReceiverParameter?.copyTo(this) + valueParameters = jvmStaticFunction.valueParameters.map { it.copyTo(this) } + } + staticExternal to companion.makeProxy(staticExternal, isStatic = false) + } else { + companion.parentAsClass.makeProxy(jvmStaticFunction, isStatic = true) to jvmStaticFunction + } + } + + private fun IrClass.makeProxy(target: IrSimpleFunction, isStatic: Boolean) = + context.irFactory.buildFun { + returnType = target.returnType + origin = JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER + // The proxy needs to have the same name as what it is targeting. If that is a property accessor, + // we need to make sure that the name is mapped correctly. The static method is not a property accessor, + // so we do not have a property to link it up to. Therefore, we compute the right name now. + name = Name.identifier(context.methodSignatureMapper.mapFunctionName(target)) + modality = if (isInterface) Modality.OPEN else target.modality + // Since we already mangle the name above we need to reset internal visibilities to public in order + // to avoid mangling the same name twice. + visibility = if (target.visibility == DescriptorVisibilities.INTERNAL) DescriptorVisibilities.PUBLIC else target.visibility + isSuspend = target.isSuspend + }.apply proxy@{ + parent = this@makeProxy + copyTypeParametersFrom(target) + copyAnnotationsFrom(target) + if (!isStatic) { + dispatchReceiverParameter = thisReceiver?.copyTo(this, type = defaultType) + } + extensionReceiverParameter = target.extensionReceiverParameter?.copyTo(this) + valueParameters = target.valueParameters.map { it.copyTo(this) } + + body = context.createIrBuilder(symbol).run { + // TODO: if the `@JvmStatic` function is inline, this inlines it into the proxy - not great (?) + // for something that's supposed to be only relevant for Java compatibility. + irExprBody(irCall(target).apply { + passTypeArgumentsFrom(this@proxy) + if (target.dispatchReceiverParameter != null) { + dispatchReceiver = irGetField(null, getFieldForObjectInstance(target.parentAsClass)) + } + extensionReceiverParameter?.let { extensionReceiver = irGet(it) } + for ((i, valueParameter) in valueParameters.withIndex()) { + putValueArgument(i, irGet(valueParameter)) + } + }) + } + } + fun getDefaultImplsFunction(interfaceFun: IrSimpleFunction, forCompatibilityMode: Boolean = false): IrSimpleFunction { val parent = interfaceFun.parentAsClass assert(parent.isJvmInterface) { "Parent of ${interfaceFun.dump()} should be interface" } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt index a3ade05d63f..ef795544dbf 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmStaticAnnotationLowering.kt @@ -9,21 +9,23 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.codegen.isEffectivelyInlineOnly +import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.addFunction -import org.jetbrains.kotlin.ir.builders.irCall -import org.jetbrains.kotlin.ir.builders.irExprBody -import org.jetbrains.kotlin.ir.builders.irGet -import org.jetbrains.kotlin.ir.builders.irGetField +import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.ir.expressions.IrTypeOperator @@ -46,131 +48,107 @@ internal val jvmStaticInCompanionPhase = makeIrFilePhase( description = "Synthesize static proxy functions for JvmStatic functions in companion objects" ) -private class JvmStaticInObjectLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { - override fun lower(irFile: IrFile) { - SingletonObjectJvmStaticLowering(context).runOnFilePostfix(irFile) - irFile.transformChildrenVoid(MakeCallsStatic(context)) - } +private class JvmStaticInObjectLowering(val context: JvmBackendContext) : FileLoweringPass { + override fun lower(irFile: IrFile) = + irFile.transformChildrenVoid(SingletonObjectJvmStaticTransformer(context)) } -private class JvmStaticInCompanionLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass { - override fun lower(irClass: IrClass) { - val companion = irClass.companionObject() ?: return - - companion.declarations - // In case of companion objects, proxy functions for '$default' methods for @JvmStatic functions with default parameters - // are not created in the host class. - .filter { - it.isJvmStaticDeclaration() && - it.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER && - it.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS - } - .forEach { declaration -> - val jvmStaticFunction = declaration as IrSimpleFunction - if (jvmStaticFunction.isExternal) { - // We move external functions to the enclosing class and potentially add accessors there. - // The JVM backend also adds accessors in the companion object, but these are superfluous. - val staticExternal = irClass.addFunction { - updateFrom(jvmStaticFunction) - name = jvmStaticFunction.name - returnType = jvmStaticFunction.returnType - }.apply { - copyTypeParametersFrom(jvmStaticFunction) - copyAnnotationsFrom(jvmStaticFunction) - extensionReceiverParameter = jvmStaticFunction.extensionReceiverParameter?.copyTo(this) - valueParameters = jvmStaticFunction.valueParameters.map { it.copyTo(this) } - } - companion.declarations.remove(jvmStaticFunction) - companion.addProxy(staticExternal, companion, isStatic = false) - } else { - irClass.addProxy(jvmStaticFunction, companion) - } - } - } - - private fun IrClass.addProxy(target: IrSimpleFunction, companion: IrClass, isStatic: Boolean = true) = - addFunction { - returnType = target.returnType - origin = JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER - // The proxy needs to have the same name as what it is targeting. If that is a property accessor, - // we need to make sure that the name is mapped correctly. The static method is not a property accessor, - // so we do not have a property to link it up to. Therefore, we compute the right name now. - name = Name.identifier(context.methodSignatureMapper.mapFunctionName(target)) - modality = if (isInterface) Modality.OPEN else target.modality - // Since we already mangle the name above we need to reset internal visibilities to public in order - // to avoid mangling the same name twice. - visibility = if (target.visibility == DescriptorVisibilities.INTERNAL) DescriptorVisibilities.PUBLIC else target.visibility - isSuspend = target.isSuspend - }.apply { - copyTypeParametersFrom(target) - copyAnnotationsFrom(target) - if (!isStatic) { - dispatchReceiverParameter = thisReceiver?.copyTo(this, type = defaultType) - } - extensionReceiverParameter = target.extensionReceiverParameter?.copyTo(this) - valueParameters = target.valueParameters.map { it.copyTo(this) } - - val proxy = this - val companionInstanceField = context.cachedDeclarations.getFieldForObjectInstance(companion) - body = context.createIrBuilder(symbol).run { - irExprBody(irCall(target).apply { - passTypeArgumentsFrom(proxy) - if (target.dispatchReceiverParameter != null) { - dispatchReceiver = irGetField(null, companionInstanceField) - } - extensionReceiverParameter?.let { extensionReceiver = irGet(it) } - for ((i, valueParameter) in valueParameters.withIndex()) { - putValueArgument(i, irGet(valueParameter)) - } - }) - } - } -} - -private class SingletonObjectJvmStaticLowering(val context: JvmBackendContext) : ClassLoweringPass { - override fun lower(irClass: IrClass) { - if (!irClass.isNonCompanionObject) return - - for (function in irClass.simpleFunctions()) { - if (function.isJvmStaticDeclaration()) { - // dispatch receiver parameter is already null for synthetic property annotation methods - function.dispatchReceiverParameter?.let { oldDispatchReceiverParameter -> - function.dispatchReceiverParameter = null - function.replaceThisByStaticReference(context.cachedDeclarations, irClass, oldDispatchReceiverParameter) - } - } - } - } -} - -internal fun IrDeclaration.isJvmStaticInObject(): Boolean = - isJvmStaticDeclaration() && (parent as? IrClass)?.isNonCompanionObject == true - -private class MakeCallsStatic(val context: JvmBackendContext) : IrElementTransformerVoid() { - override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression { - val callee = expression.symbol.owner - if (callee is IrDeclaration && callee.isJvmStaticInObject() && expression.dispatchReceiver != null) { - expression.transformChildrenVoid() - return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) { - // OldReceiver has to be evaluated for its side effects. - val oldReceiver = super.visitExpression(expression.dispatchReceiver!!) - // `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here - +IrTypeOperatorCallImpl( - oldReceiver.startOffset, oldReceiver.endOffset, - context.irBuiltIns.unitType, - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, - context.irBuiltIns.unitType, - oldReceiver - ) - expression.dispatchReceiver = null - +super.visitMemberAccess(expression) - } - } - return super.visitMemberAccess(expression) - } +private class JvmStaticInCompanionLowering(val context: JvmBackendContext) : FileLoweringPass { + override fun lower(irFile: IrFile) = + irFile.transformChildrenVoid(CompanionObjectJvmStaticTransformer(context)) } private fun IrDeclaration.isJvmStaticDeclaration(): Boolean = hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) || (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true || (this as? IrProperty)?.getter?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true + +private fun IrDeclaration.isJvmStaticInCompanion(): Boolean = + isJvmStaticDeclaration() && (parent as? IrClass)?.isCompanion == true + +internal fun IrDeclaration.isJvmStaticInObject(): Boolean = + isJvmStaticDeclaration() && (parent as? IrClass)?.isNonCompanionObject == true + +// `coerceToUnit()` is private in InsertImplicitCasts, have to reproduce it here +private fun IrExpression.coerceToUnit(irBuiltIns: IrBuiltIns) = + IrTypeOperatorCallImpl(startOffset, endOffset, irBuiltIns.unitType, IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, irBuiltIns.unitType, this) + +private fun IrMemberAccessExpression<*>.makeStatic(context: JvmBackendContext, replaceCallee: IrSimpleFunction?) = + dispatchReceiver?.let { receiver -> + dispatchReceiver = null + // Not really the right symbol, but we don't use the scope here anyway. + context.createIrBuilder(symbol).irBlock(startOffset, endOffset) { + +receiver.coerceToUnit(context.irBuiltIns) // evaluate for side effects + +if (replaceCallee != null) irCall(this@makeStatic as IrCall, replaceCallee) else this@makeStatic + } + } ?: this + +private class SingletonObjectJvmStaticTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() { + override fun visitClass(declaration: IrClass): IrStatement { + if (declaration.isNonCompanionObject) { + for (function in declaration.simpleFunctions()) { + if (function.isJvmStaticDeclaration()) { + // dispatch receiver parameter is already null for synthetic property annotation methods + function.dispatchReceiverParameter?.let { oldDispatchReceiverParameter -> + function.dispatchReceiverParameter = null + function.replaceThisByStaticReference(context.cachedDeclarations, declaration, oldDispatchReceiverParameter) + } + } + } + } + return super.visitClass(declaration) + } + + // This lowering runs before functions references are handled, and should transform them too. + override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression { + expression.transformChildrenVoid(this) + val callee = expression.symbol.owner + if (callee is IrDeclaration && callee.isJvmStaticInObject()) { + return expression.makeStatic(context, replaceCallee = null) + } + return expression + } +} + +private class CompanionObjectJvmStaticTransformer(val context: JvmBackendContext) : IrElementTransformerVoid() { + // TODO: would be nice to add a mode that *only* leaves static versions for all annotated methods, with nothing + // in companions - this would reduce the number of classes if the companion only has `@JvmStatic` declarations. + private fun IrSimpleFunction.needsStaticProxy(): Boolean = when { + // Case 1: `external` static methods are moved to the outer class. JNI code does not care about visibility. + isExternal -> true + // Case 2: `JvmStatic` is useless on private/inline-only methods because they're not visible to any Java code anyway. + visibility == DescriptorVisibilities.PRIVATE -> false + visibility == DescriptorVisibilities.PRIVATE_TO_THIS -> false + origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS -> false + isEffectivelyInlineOnly() -> false + // Case 3: protected non-inline needs a static proxy in the parent to be callable from subclasses + // of said parent in different packages even in pure Kotlin due to JVM visibility rules. + visibility == DescriptorVisibilities.PROTECTED && !isInline -> true + // Case 4: public or protected inline needs a static proxy if not synthetic to be callable + // on the parent class from Java code (the original point of this annotation). + else -> !origin.isSynthetic + } + + override fun visitClass(declaration: IrClass): IrStatement = + super.visitClass(declaration).also { + declaration.companionObject()?.declarations?.transformInPlace { + if (it is IrSimpleFunction && it.isJvmStaticDeclaration() && it.needsStaticProxy()) { + val (static, companionFun) = context.cachedDeclarations.getStaticAndCompanionDeclaration(it) + declaration.declarations.add(static) + companionFun + } else it + } + } + + // By this point all callable references have already been lowered (except ones for signature-generating + // intrinsics, which do not care about accessibility rules), so only calls remain. + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + val callee = expression.symbol.owner + if (callee.isJvmStaticInCompanion() && callee.visibility == DescriptorVisibilities.PROTECTED && !callee.isInlineFunctionCall(context)) { + val (staticProxy, _) = context.cachedDeclarations.getStaticAndCompanionDeclaration(callee) + return expression.makeStatic(context, staticProxy) + } + return expression + } +} diff --git a/compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt b/compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt new file mode 100644 index 00000000000..b5f5d7fd017 --- /dev/null +++ b/compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt @@ -0,0 +1,21 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// WITH_RUNTIME +// FILE: 1.kt +package a + +open class A { + companion object { + @JvmStatic // Required to be accessible from subclasses of A in other packages. + protected fun foo() = "OK" + } +} + +// FILE: 2.kt +import a.* + +class B : A() { + fun bar() = foo() // calls static A.foo(), not inaccessible A.Companion.foo() +} + +fun box() = B().bar() diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 2d7ad275648..296a822131e 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -23472,6 +23472,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/jvmStatic/companionObject.kt"); } + @Test + @TestMetadata("companionObjectProtected.kt") + public void testCompanionObjectProtected() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt"); + } + @Test @TestMetadata("convention.kt") public void testConvention() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 5c53ee8f893..358e4de8f76 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -23490,6 +23490,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/jvmStatic/companionObject.kt"); } + @Test + @TestMetadata("companionObjectProtected.kt") + public void testCompanionObjectProtected() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt"); + } + @Test @TestMetadata("convention.kt") public void testConvention() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 3e06fa0e6cd..d0cae79930b 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -19761,6 +19761,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class JvmStatic extends AbstractLightAnalysisModeTest { + @TestMetadata("companionObjectProtected.kt") + public void ignoreCompanionObjectProtected() throws Exception { + runTest("compiler/testData/codegen/box/jvmStatic/companionObjectProtected.kt"); + } + @TestMetadata("extensionPropertyGetter.kt") public void ignoreExtensionPropertyGetter() throws Exception { runTest("compiler/testData/codegen/box/jvmStatic/extensionPropertyGetter.kt");