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 49da18d87ad..72770f35271 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 @@ -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) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index c6cfeb0c1b4..119d4cb00fb 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -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 -> diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 9a24f4083e0..8f42b0ec8d3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt index d6815d20c8e..17f77b52e3e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt @@ -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) + } + } } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt index 94e29163406..9138c5f9f50 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ObjectClassLowering.kt @@ -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) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index d7431b7079f..98c65048016 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -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): List { + return annotations.filterNot { it.annotationClass.hasEqualFqName(fqName) } +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/javaDeprecated.kt b/compiler/testData/codegen/bytecodeListing/javaDeprecated.kt new file mode 100644 index 00000000000..d33ced0088d --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/javaDeprecated.kt @@ -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() {} + +} diff --git a/compiler/testData/codegen/bytecodeListing/javaDeprecated.txt b/compiler/testData/codegen/bytecodeListing/javaDeprecated.txt new file mode 100644 index 00000000000..ef52d56f0a7 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/javaDeprecated.txt @@ -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 (): 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 +} diff --git a/compiler/testData/codegen/bytecodeListing/privateCompanionFields_ir.txt b/compiler/testData/codegen/bytecodeListing/privateCompanionFields_ir.txt new file mode 100644 index 00000000000..3655a8501c8 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/privateCompanionFields_ir.txt @@ -0,0 +1,57 @@ +@kotlin.Metadata +final class TestClass$Companion { + // source: 'privateCompanionFields.kt' + private method (): void + public synthetic method (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 (): void + public method (): 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 (): void + private method (): 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 (): 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 (): void + private method (): 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 (): void + public final inner class TestJvmField$Companion +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index bcf7e04db6b..dd8f24d5a5b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 176cdcccde2..ce84db6b03b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -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");