Deprecate public access to @JvmField/const fields in private companions

#KT-25009
This commit is contained in:
Mikhael Bogdanov
2020-10-27 14:42:06 +01:00
parent 8be23df668
commit 57c9afc73a
9 changed files with 132 additions and 7 deletions
@@ -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);
@@ -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<String> 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
@@ -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<String> 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);
}
}
}
@@ -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,
@@ -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"
}
}
@@ -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 @org.jetbrains.annotations.NotNull 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
private method <init>(): void
public synthetic method <init>(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 <clinit>(): void
public final inner class TestJvmField$Companion
}
@@ -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");
@@ -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");
@@ -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