JVM_IR. Deprecate public access to @JvmField/const fields in private companions
#KT-25009
This commit is contained in:
+17
-6
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.MethodSignatureMapper
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping
|
||||
import org.jetbrains.kotlin.builtins.isMappedIntrinsicCompanionObjectClassId
|
||||
@@ -122,11 +123,21 @@ class JvmCachedDeclarations(
|
||||
// It is an error to annotate only some of the fields of an interface companion with
|
||||
// @JvmField, so checking the current field only should be enough.
|
||||
val hasJvmField = oldField.hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME)
|
||||
parent = if (oldParent.isCompanion && (!oldParent.parentAsClass.isJvmInterface || hasJvmField))
|
||||
oldParent.parentAsClass
|
||||
else
|
||||
oldParent
|
||||
annotations += oldField.annotations
|
||||
if (oldParent.isCompanion && (!oldParent.parentAsClass.isJvmInterface || hasJvmField)) {
|
||||
parent = oldParent.parentAsClass
|
||||
annotations = if (DescriptorVisibilities.isPrivate(oldParent.visibility)) {
|
||||
context.createJvmIrBuilder(this.symbol).run {
|
||||
filterOutAnnotations(
|
||||
DeprecationResolver.JAVA_DEPRECATED,
|
||||
oldField.annotations
|
||||
) + irCall(irSymbols.javaLangDeprecatedConstructorWithDeprecatedFlag)
|
||||
}
|
||||
} else oldField.annotations
|
||||
} else {
|
||||
parent = oldParent
|
||||
annotations = oldField.annotations
|
||||
}
|
||||
|
||||
initializer = oldField.initializer
|
||||
?.replaceThisByStaticReference(this@JvmCachedDeclarations, oldParent, oldParent.thisReceiver!!)
|
||||
?.patchDeclarationParents(this) as IrExpressionBody?
|
||||
@@ -183,7 +194,7 @@ class JvmCachedDeclarations(
|
||||
!it.annotations.hasAnnotation(DeprecationResolver.JAVA_DEPRECATED)
|
||||
) {
|
||||
this@JvmCachedDeclarations.context.createIrBuilder(it.symbol).run {
|
||||
it.annotations += irCall(this@JvmCachedDeclarations.context.ir.symbols.javaLangDeprecatedConstructor)
|
||||
it.annotations += irCall(this@JvmCachedDeclarations.context.ir.symbols.javaLangDeprecatedConstructorWithDeprecatedFlag)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -208,12 +208,13 @@ class JvmSymbols(
|
||||
klass.addFunction("desiredAssertionStatus", irBuiltIns.booleanType)
|
||||
}
|
||||
|
||||
private val javaLangDeprecated: IrClassSymbol =
|
||||
private val javaLangDeprecatedWithDeprecatedFlag: IrClassSymbol =
|
||||
createClass(FqName("java.lang.Deprecated")) { klass ->
|
||||
klass.addConstructor { isPrimary = true }
|
||||
}
|
||||
|
||||
val javaLangDeprecatedConstructor = javaLangDeprecated.constructors.single()
|
||||
// This annotations also implies ACC_DEPRECATED flag in generated bytecode
|
||||
val javaLangDeprecatedConstructorWithDeprecatedFlag = javaLangDeprecatedWithDeprecatedFlag.constructors.single()
|
||||
|
||||
private val javaLangAssertionError: IrClassSymbol =
|
||||
createClass(FqName("java.lang.AssertionError"), classModality = Modality.OPEN) { klass ->
|
||||
|
||||
+5
-7
@@ -281,7 +281,7 @@ class ClassCodegen private constructor(
|
||||
if (field.origin == IrDeclarationOrigin.PROPERTY_DELEGATE) null
|
||||
else context.methodSignatureMapper.mapFieldSignature(field)
|
||||
val fieldName = field.name.asString()
|
||||
val flags = field.computeFieldFlags(state.languageVersionSettings)
|
||||
val flags = field.computeFieldFlags(context, state.languageVersionSettings)
|
||||
val fv = visitor.newField(
|
||||
field.descriptorOrigin, flags, fieldName, fieldType.descriptor,
|
||||
fieldSignature, (field.initializer?.expression as? IrConst<*>)?.value
|
||||
@@ -455,10 +455,10 @@ private val IrClass.flags: Int
|
||||
else -> Opcodes.ACC_SUPER or modality.flags
|
||||
}
|
||||
|
||||
private fun IrField.computeFieldFlags(languageVersionSettings: LanguageVersionSettings): Int =
|
||||
private fun IrField.computeFieldFlags(context: JvmBackendContext, languageVersionSettings: LanguageVersionSettings): Int =
|
||||
origin.flags or visibility.flags or
|
||||
(correspondingPropertySymbol?.owner?.callableDeprecationFlags ?: 0) or
|
||||
(if (shouldHaveSpecialDeprecationFlag()) Opcodes.ACC_DEPRECATED else 0) or
|
||||
(if (shouldHaveSpecialDeprecationFlag(context)) Opcodes.ACC_DEPRECATED else 0) or
|
||||
(if (annotations.hasAnnotation(KOTLIN_DEPRECATED)) Opcodes.ACC_DEPRECATED else 0) or
|
||||
(if (isFinal) Opcodes.ACC_FINAL else 0) or
|
||||
(if (isStatic) Opcodes.ACC_STATIC else 0) or
|
||||
@@ -474,12 +474,10 @@ private fun IrField.isPrivateCompanionFieldInInterface(languageVersionSettings:
|
||||
parentAsClass.isJvmInterface &&
|
||||
DescriptorVisibilities.isPrivate(parentAsClass.companionObject()!!.visibility)
|
||||
|
||||
private val JAVA_LANG_DEPRECATED = FqName("java.lang.Deprecated")
|
||||
private val KOTLIN_DEPRECATED = FqName("kotlin.Deprecated")
|
||||
|
||||
fun IrField.shouldHaveSpecialDeprecationFlag(): Boolean {
|
||||
return origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE &&
|
||||
annotations.hasAnnotation(JAVA_LANG_DEPRECATED)
|
||||
fun IrField.shouldHaveSpecialDeprecationFlag(context: JvmBackendContext): Boolean {
|
||||
return annotations.any { it.symbol == context.ir.symbols.javaLangDeprecatedConstructorWithDeprecatedFlag }
|
||||
}
|
||||
|
||||
private val IrDeclarationOrigin.flags: Int
|
||||
|
||||
+12
@@ -7,13 +7,16 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||
import org.jetbrains.kotlin.backend.jvm.propertiesPhase
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addProperty
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -21,10 +24,12 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.filterOutAnnotations
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
internal val moveOrCopyCompanionObjectFieldsPhase = makeIrFilePhase(
|
||||
::MoveOrCopyCompanionObjectFieldsLowering,
|
||||
@@ -124,6 +129,13 @@ private class MoveOrCopyCompanionObjectFieldsLowering(val context: JvmBackendCon
|
||||
initializer = with(oldField.initializer!!) {
|
||||
IrExpressionBodyImpl(startOffset, endOffset, (expression as IrConst<*>).copy())
|
||||
}
|
||||
|
||||
if (oldProperty.parentAsClass.visibility == DescriptorVisibilities.PRIVATE) {
|
||||
context.createJvmIrBuilder(this.symbol).run {
|
||||
annotations = filterOutAnnotations(DeprecationResolver.JAVA_DEPRECATED, annotations) +
|
||||
irCall(irSymbols.javaLangDeprecatedConstructorWithDeprecatedFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.builders.irExprBody
|
||||
import org.jetbrains.kotlin.ir.builders.irGetField
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
internal val objectClassPhase = makeIrFilePhase(
|
||||
::ObjectClassLowering,
|
||||
@@ -72,8 +73,9 @@ private class ObjectClassLowering(val context: JvmBackendContext) : IrElementTra
|
||||
(irClass.visibility == DescriptorVisibilities.PRIVATE || irClass.visibility == DescriptorVisibilities.PROTECTED)
|
||||
) {
|
||||
context.createIrBuilder(irClass.symbol).run {
|
||||
publicInstanceField.annotations +=
|
||||
irCall(this@ObjectClassLowering.context.ir.symbols.javaLangDeprecatedConstructor)
|
||||
publicInstanceField.annotations =
|
||||
filterOutAnnotations(DeprecationResolver.JAVA_DEPRECATED, publicInstanceField.annotations) +
|
||||
irCall(this@ObjectClassLowering.context.ir.symbols.javaLangDeprecatedConstructorWithDeprecatedFlag)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,3 +245,7 @@ fun IrClassSymbol.getPropertySetter(name: String): IrSimpleFunctionSymbol? = own
|
||||
|
||||
inline fun MemberScope.findFirstFunction(name: String, predicate: (CallableMemberDescriptor) -> Boolean) =
|
||||
getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).first(predicate)
|
||||
|
||||
fun filterOutAnnotations(fqName: FqName, annotations: List<IrConstructorCall>): List<IrConstructorCall> {
|
||||
return annotations.filterNot { it.annotationClass.hasEqualFqName(fqName) }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
@field:java.lang.Deprecated
|
||||
val bar: String = "123"
|
||||
|
||||
@java.lang.Deprecated
|
||||
val bar2: String = "123"
|
||||
|
||||
@java.lang.Deprecated
|
||||
fun test() {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@kotlin.Metadata
|
||||
public final class Foo {
|
||||
// source: 'javaDeprecated.kt'
|
||||
private final @java.lang.Deprecated @org.jetbrains.annotations.NotNull field bar2: java.lang.String
|
||||
private final @java.lang.Deprecated @org.jetbrains.annotations.NotNull field bar: java.lang.String
|
||||
public method <init>(): void
|
||||
public final @org.jetbrains.annotations.NotNull method getBar(): java.lang.String
|
||||
public final @org.jetbrains.annotations.NotNull method getBar2(): java.lang.String
|
||||
public final @java.lang.Deprecated method test(): void
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
@kotlin.Metadata
|
||||
final class TestClass$Companion {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
private method <init>(): void
|
||||
public synthetic method <init>(p0: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private final inner class TestClass$Companion
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class TestClass {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
private final static @org.jetbrains.annotations.NotNull field Companion: TestClass$Companion
|
||||
public deprecated static @java.lang.Deprecated @kotlin.jvm.JvmField @org.jetbrains.annotations.NotNull field test2: java.lang.String
|
||||
public deprecated final static @java.lang.Deprecated @kotlin.jvm.JvmField @org.jetbrains.annotations.NotNull field test3: java.lang.String
|
||||
public deprecated static @java.lang.Deprecated @kotlin.jvm.JvmField @org.jetbrains.annotations.NotNull field test: java.lang.String
|
||||
public deprecated final static @java.lang.Deprecated field testConst: int
|
||||
static method <clinit>(): void
|
||||
public method <init>(): void
|
||||
private final inner class TestClass$Companion
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TestConst$Companion {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
synthetic final static field $$INSTANCE: TestConst$Companion
|
||||
public final static field testConst: int
|
||||
static method <clinit>(): void
|
||||
private method <init>(): void
|
||||
public final inner class TestConst$Companion
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public interface TestConst {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
public synthetic final static field Companion: TestConst$Companion
|
||||
public deprecated final static @java.lang.Deprecated field testConst: int
|
||||
static method <clinit>(): void
|
||||
public final inner class TestConst$Companion
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class TestJvmField$Companion {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
synthetic final static field $$INSTANCE: TestJvmField$Companion
|
||||
static method <clinit>(): void
|
||||
private method <init>(): void
|
||||
public final inner class TestJvmField$Companion
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public interface TestJvmField {
|
||||
// source: 'privateCompanionFields.kt'
|
||||
public synthetic final static field Companion: TestJvmField$Companion
|
||||
public deprecated final static @java.lang.Deprecated @kotlin.jvm.JvmField @org.jetbrains.annotations.NotNull field test3: java.lang.String
|
||||
static method <clinit>(): void
|
||||
public final inner class TestJvmField$Companion
|
||||
}
|
||||
+5
@@ -84,6 +84,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaDeprecated.kt")
|
||||
public void testJavaDeprecated() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/javaDeprecated.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmOverloadsAndParametersAnnotations.kt")
|
||||
public void testJvmOverloadsAndParametersAnnotations() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/jvmOverloadsAndParametersAnnotations.kt");
|
||||
|
||||
+5
@@ -84,6 +84,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaDeprecated.kt")
|
||||
public void testJavaDeprecated() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/javaDeprecated.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmOverloadsAndParametersAnnotations.kt")
|
||||
public void testJvmOverloadsAndParametersAnnotations() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/jvmOverloadsAndParametersAnnotations.kt");
|
||||
|
||||
Reference in New Issue
Block a user