From 57c9afc73afdcdbb5d9483de22850565ff2c17ae Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 27 Oct 2020 14:42:06 +0100 Subject: [PATCH] Deprecate public access to @JvmField/const fields in private companions #KT-25009 --- .../kotlin/codegen/FunctionCodegen.java | 3 +- .../codegen/ImplementationBodyCodegen.java | 13 ++++- .../kotlin/codegen/PropertyCodegen.java | 8 ++- .../jetbrains/kotlin/codegen/codegenUtil.kt | 6 +- .../bytecodeListing/privateCompanionFields.kt | 32 +++++++++++ .../privateCompanionFields.txt | 57 +++++++++++++++++++ .../codegen/BytecodeListingTestGenerated.java | 5 ++ .../ir/IrBytecodeListingTestGenerated.java | 5 ++ .../stubBuilder/Annotations/Annotations.txt | 10 ++++ 9 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt create mode 100644 compiler/testData/codegen/bytecodeListing/privateCompanionFields.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 0e0cc818355..3bc84e5c944 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -85,7 +85,6 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class FunctionCodegen { - private static final String JAVA_LANG_DEPRECATED = Type.getType(Deprecated.class).getDescriptor(); public final GenerationState state; private final KotlinTypeMapper typeMapper; @@ -225,7 +224,7 @@ public class FunctionCodegen { InlineClassDescriptorResolver.isSpecializedEqualsMethod(functionDescriptor); generateMethodAnnotationsIfRequired( functionDescriptor, asmMethod, jvmSignature, mv, - isCompatibilityStubInDefaultImpls ? Collections.singletonList(JAVA_LANG_DEPRECATED) : Collections.emptyList(), + isCompatibilityStubInDefaultImpls ? Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED) : Collections.emptyList(), skipNullabilityAnnotations ); GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 27a5e100f0b..2f0cf3eef55 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -903,19 +903,26 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateCompanionObjectBackingFieldCopies() { - if (companionObjectPropertiesToCopy == null) return; + if (companionObjectPropertiesToCopy == null || companionObjectPropertiesToCopy.isEmpty()) return; + boolean isPrivateCompanion = + DescriptorVisibilities.isPrivate( + ((ClassDescriptor) companionObjectPropertiesToCopy.get(0).descriptor.getContainingDeclaration()).getVisibility()); + + int modifiers = ACC_STATIC | ACC_FINAL | ACC_PUBLIC | (isPrivateCompanion ? ACC_DEPRECATED : 0); + List additionalVisibleAnnotations = + isPrivateCompanion ? Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED) : Collections.emptyList(); for (PropertyAndDefaultValue info : companionObjectPropertiesToCopy) { PropertyDescriptor property = info.descriptor; Type type = typeMapper.mapType(property); - int modifiers = ACC_STATIC | ACC_FINAL | ACC_PUBLIC; + FieldVisitor fv = v.newField(JvmDeclarationOriginKt.Synthetic(DescriptorToSourceUtils.descriptorToDeclaration(property), property), modifiers, context.getFieldName(property, false), type.getDescriptor(), typeMapper.mapFieldSignature(property.getType(), property), info.defaultValue); - AnnotationCodegen.forField(fv, this, state).genAnnotations(property, type, null); + AnnotationCodegen.forField(fv, this, state).genAnnotations(property, type, null, null, additionalVisibleAnnotations); //This field are always static and final so if it has constant initializer don't do anything in clinit, //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index c50baeac347..c10a8e61814 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -42,6 +42,7 @@ import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; +import java.util.Collections; import java.util.List; import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getDeprecatedAccessFlag; @@ -408,6 +409,7 @@ public class PropertyCodegen { ClassBuilder builder = v; FieldOwnerContext backingFieldContext = context; + List additionalVisibleAnnotations = Collections.emptyList(); if (DescriptorAsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) { modifiers |= ACC_STATIC; @@ -415,6 +417,10 @@ public class PropertyCodegen { ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); builder = codegen.v; backingFieldContext = codegen.context; + if (DescriptorVisibilities.isPrivate(((ClassDescriptor) propertyDescriptor.getContainingDeclaration()).getVisibility())) { + modifiers |= ACC_DEPRECATED; + additionalVisibleAnnotations = Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED); + } } } modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate); @@ -442,7 +448,7 @@ public class PropertyCodegen { (modifiers & ACC_SYNTHETIC) != 0 || propertyDescriptor.isLateInit(); AnnotationCodegen.forField(fv, memberCodegen, state, skipNullabilityAnnotations) - .genAnnotations(annotatedField, type, propertyDescriptor.getType()); + .genAnnotations(annotatedField, type, propertyDescriptor.getType(), null, additionalVisibleAnnotations); } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 88dcc1a093e..b7521d00ee2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -24,8 +24,8 @@ import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.SpecialSignatureInfo import org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil +import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.SpecialSignatureInfo import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -60,8 +60,12 @@ import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.LabelNode +import java.lang.Deprecated import java.util.* +@JvmField +internal val JAVA_LANG_DEPRECATED = Type.getType(Deprecated::class.java).descriptor + fun generateIsCheck( v: InstructionAdapter, kotlinType: KotlinType, diff --git a/compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt b/compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt new file mode 100644 index 00000000000..e20aa87dacd --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt @@ -0,0 +1,32 @@ +// WITH_RUNTIME +class TestClass { + + private companion object { + @JvmField + var test: String = "1" + + @JvmField + @java.lang.Deprecated + var test2: String = "2" + + @JvmField + val test3: String = "3" + + const val testConst = 1 + } +} + +interface TestConst { + + private companion object { + const val testConst = 1 + } +} + +interface TestJvmField { + + private companion object { + @JvmField + val test3: String = "3" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/privateCompanionFields.txt b/compiler/testData/codegen/bytecodeListing/privateCompanionFields.txt new file mode 100644 index 00000000000..1dcbba75727 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/privateCompanionFields.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 @org.jetbrains.annotations.NotNull 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 + private method (): void + public synthetic method (p0: kotlin.jvm.internal.DefaultConstructorMarker): void + public final inner class TestJvmField$Companion +} + +@kotlin.Metadata +public interface TestJvmField { + // source: 'privateCompanionFields.kt' + public synthetic final static @org.jetbrains.annotations.NotNull 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 d517d4b2cfa..bcf7e04db6b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -134,6 +134,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/noToArrayInJava.kt"); } + @TestMetadata("privateCompanionFields.kt") + public void testPrivateCompanionFields() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt"); + } + @TestMetadata("privateDefaultImpls.kt") public void testPrivateDefaultImpls() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/privateDefaultImpls.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index 601a7f227ca..176cdcccde2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -134,6 +134,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/noToArrayInJava.kt"); } + @TestMetadata("privateCompanionFields.kt") + public void testPrivateCompanionFields() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/privateCompanionFields.kt"); + } + @TestMetadata("privateDefaultImpls.kt") public void testPrivateDefaultImpls() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/privateDefaultImpls.kt"); diff --git a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt index a349c6650af..a67510bc1f7 100644 --- a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt +++ b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt @@ -52,6 +52,16 @@ PsiJetFileStubImpl[package=] TYPE_REFERENCE USER_TYPE REFERENCE_EXPRESSION[referencedName=f] + ANNOTATION_ENTRY[hasValueArguments=false, shortName=Deprecated] + ANNOTATION_TARGET[useSiteTarget=FIELD] + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + USER_TYPE + USER_TYPE + REFERENCE_EXPRESSION[referencedName=java] + REFERENCE_EXPRESSION[referencedName=lang] + REFERENCE_EXPRESSION[referencedName=Deprecated] TYPE_REFERENCE USER_TYPE USER_TYPE