Generate metadata and annotations for hidden constructor
Reflection expects to see a callable method for a hidden constructor, thus, it should be a synthetic accessor. JVM method signature in metadata should point to the synthetic accessor. Annotations for hidden constructor should be written on the synthetic accessor.
This commit is contained in:
@@ -76,6 +76,7 @@ import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isEf
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmDefaultAnnotation;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
@@ -226,13 +227,10 @@ public class FunctionCodegen {
|
||||
asmMethod.getDescriptor()
|
||||
);
|
||||
|
||||
if (CodegenContextUtil.isImplementationOwner(owner, functionDescriptor)) {
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod);
|
||||
}
|
||||
recordMethodForFunctionIfAppropriate(functionDescriptor, asmMethod);
|
||||
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(functionDescriptor, asmMethod.getReturnType());
|
||||
generateMethodAnnotationsIfRequired(functionDescriptor, asmMethod, jvmSignature, mv);
|
||||
|
||||
generateParameterAnnotations(functionDescriptor, mv, jvmSignature, memberCodegen, state);
|
||||
GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0);
|
||||
|
||||
if (contextKind != OwnerKind.ERASED_INLINE_CLASS) {
|
||||
@@ -269,6 +267,49 @@ public class FunctionCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void recordMethodForFunctionIfAppropriate(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
Method asmMethod
|
||||
) {
|
||||
if (functionDescriptor instanceof AccessorForConstructorDescriptor) {
|
||||
ConstructorDescriptor originalConstructor = ((AccessorForConstructorDescriptor) functionDescriptor).getCalleeDescriptor();
|
||||
if (shouldHideConstructorDueToInlineClassTypeValueParameters(originalConstructor)) {
|
||||
functionDescriptor = originalConstructor;
|
||||
}
|
||||
}
|
||||
else if (shouldHideConstructorDueToInlineClassTypeValueParameters(functionDescriptor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
functionDescriptor = CodegenUtilKt.unwrapFrontendVersion(functionDescriptor);
|
||||
|
||||
if (!CodegenContextUtil.isImplementationOwner(owner, functionDescriptor)) return;
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
|
||||
}
|
||||
|
||||
private void generateMethodAnnotationsIfRequired(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull Method asmMethod,
|
||||
@NotNull JvmMethodGenericSignature jvmSignature,
|
||||
@NotNull MethodVisitor mv
|
||||
) {
|
||||
FunctionDescriptor annotationsOwner;
|
||||
if (shouldHideConstructorDueToInlineClassTypeValueParameters(functionDescriptor)) {
|
||||
if (functionDescriptor instanceof AccessorForConstructorDescriptor) {
|
||||
annotationsOwner = ((AccessorForConstructorDescriptor) functionDescriptor).getCalleeDescriptor();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
annotationsOwner = functionDescriptor;
|
||||
}
|
||||
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(annotationsOwner, asmMethod.getReturnType());
|
||||
generateParameterAnnotations(annotationsOwner, mv, jvmSignature, memberCodegen, state);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodVisitor newMethod(
|
||||
@NotNull JvmDeclarationOrigin origin,
|
||||
|
||||
@@ -28,7 +28,7 @@ object KotlinStubVersions {
|
||||
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
|
||||
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
|
||||
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
|
||||
private const val BINARY_STUB_VERSION = 69
|
||||
private const val BINARY_STUB_VERSION = 70
|
||||
|
||||
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
|
||||
// Increasing this version will lead to reindexing of all classfiles.
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
annotation class Ann
|
||||
|
||||
inline class Z(val x: Int)
|
||||
|
||||
class Test @Ann constructor(@Ann val z: Z) {
|
||||
@Ann constructor(z: Z, @Ann a: Int) : this(z)
|
||||
@Ann private constructor(z: Z, @Ann s: String) : this(z)
|
||||
|
||||
inner class Inner @Ann constructor(x: Int, @Ann val z2: Z, @Ann y: String)
|
||||
}
|
||||
|
||||
sealed class Sealed @Ann constructor(@Ann val z: Z) {
|
||||
class Derived @Ann constructor(z: Z) : Sealed(z)
|
||||
|
||||
inner class Inner @Ann constructor(x: Int, @Ann val z2: Z, @Ann y: String)
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class Ann
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Sealed$Derived {
|
||||
inner class Sealed$Derived
|
||||
private method <init>(p0: int): void
|
||||
public synthetic @Ann method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Sealed$Inner {
|
||||
synthetic final field this$0: Sealed
|
||||
private final field z2: int
|
||||
inner class Sealed$Inner
|
||||
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Sealed, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private method <init>(p0: Sealed, p1: int, p2: int, p3: java.lang.String): void
|
||||
public final method getZ2(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public abstract class Sealed {
|
||||
private final field z: int
|
||||
inner class Sealed$Derived
|
||||
inner class Sealed$Inner
|
||||
private @Ann method <init>(@Ann p0: int): void
|
||||
public synthetic method <init>(@Ann p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
public final method getZ(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Test$Inner {
|
||||
synthetic final field this$0: Test
|
||||
private final field z2: int
|
||||
inner class Test$Inner
|
||||
public synthetic @Ann method <init>(@java.lang.Synthetic p0: Test, p1: int, @Ann p2: int, @Ann p3: java.lang.String, p4: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private method <init>(p0: Test, p1: int, p2: int, p3: java.lang.String): void
|
||||
public final method getZ2(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Test {
|
||||
private final field z: int
|
||||
inner class Test$Inner
|
||||
public synthetic @Ann method <init>(@Ann p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private method <init>(p0: int): void
|
||||
public synthetic @Ann method <init>(p0: int, @Ann p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private @Ann method <init>(p0: int, @Ann p1: java.lang.String): void
|
||||
private method <init>(p0: int, p1: int): void
|
||||
public final method getZ(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class Z {
|
||||
private final field x: int
|
||||
private synthetic method <init>(p0: int): void
|
||||
public synthetic final static @org.jetbrains.annotations.NotNull method box-impl(p0: int): Z
|
||||
public static method constructor-impl(p0: int): int
|
||||
public method equals(p0: java.lang.Object): boolean
|
||||
public static method equals-impl(p0: int, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean
|
||||
public final static method equals-impl0(p0: int, p1: int): boolean
|
||||
public final method getX(): int
|
||||
public method hashCode(): int
|
||||
public static method hashCode-impl(p0: int): int
|
||||
public method toString(): java.lang.String
|
||||
public static @org.jetbrains.annotations.NotNull method toString-impl(p0: int): java.lang.String
|
||||
public synthetic final method unbox-impl(): int
|
||||
}
|
||||
Vendored
+2
-2
@@ -11,11 +11,11 @@ public interface PublicMarker
|
||||
public class TestBasic {
|
||||
private final field z: int
|
||||
private method <init>(p0: int): void
|
||||
public synthetic method <init>(p0: int, @org.jetbrains.annotations.NotNull p1: ProtectedMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
public synthetic method <init>(p0: int, @org.jetbrains.annotations.NotNull p1: PublicMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private method <init>(p0: int, p1: PrivateMarker): void
|
||||
private method <init>(p0: int, p1: ProtectedMarker): void
|
||||
public synthetic method <init>(p0: int, p1: ProtectedMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
private method <init>(p0: int, p1: PublicMarker): void
|
||||
public synthetic method <init>(p0: int, p1: PublicMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
public synthetic method <init>(p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
public final method getZ(): int
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
package test
|
||||
|
||||
annotation class Ann
|
||||
|
||||
inline class Z(val x: Int)
|
||||
|
||||
class Test @Ann constructor(@Ann val z: Z) {
|
||||
@Ann constructor(z: Z, @Ann a: Int) : this(z)
|
||||
@Ann private constructor(z: Z, @Ann s: String) : this(z)
|
||||
}
|
||||
|
||||
sealed class Sealed @Ann constructor(@Ann val z: Z) {
|
||||
class Derived @Ann constructor(z: Z) : Sealed(z)
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package test
|
||||
|
||||
public final annotation class Ann : kotlin.Annotation {
|
||||
/*primary*/ public constructor Ann()
|
||||
}
|
||||
|
||||
public sealed class Sealed {
|
||||
/*primary*/ @test.Ann private constructor Sealed(/*0*/ @test.Ann z: test.Z)
|
||||
public final val z: test.Z
|
||||
public final fun <get-z>(): test.Z
|
||||
|
||||
public final class Derived : test.Sealed {
|
||||
/*primary*/ @test.Ann public constructor Derived(/*0*/ z: test.Z)
|
||||
public final override /*1*/ /*fake_override*/ val z: test.Z
|
||||
public final override /*1*/ /*fake_override*/ fun <get-z>(): test.Z
|
||||
}
|
||||
}
|
||||
|
||||
public final class Test {
|
||||
/*primary*/ @test.Ann public constructor Test(/*0*/ @test.Ann z: test.Z)
|
||||
@test.Ann public constructor Test(/*0*/ z: test.Z, /*1*/ @test.Ann a: kotlin.Int)
|
||||
@test.Ann private constructor Test(/*0*/ z: test.Z, /*1*/ @test.Ann s: kotlin.String)
|
||||
public final val z: test.Z
|
||||
public final fun <get-z>(): test.Z
|
||||
}
|
||||
|
||||
public final inline class Z {
|
||||
/*primary*/ public constructor Z(/*0*/ x: kotlin.Int)
|
||||
public final val x: kotlin.Int
|
||||
public final fun <get-x>(): kotlin.Int
|
||||
}
|
||||
+5
@@ -274,6 +274,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnHiddenConstructor.kt")
|
||||
public void testAnnotationsOnHiddenConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotationsOnHiddenConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("companionObjectInsideInlineClass.kt")
|
||||
public void testCompanionObjectInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.kt");
|
||||
|
||||
@@ -1789,6 +1789,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("HiddenConstructorWithInlineClassParameters.kt")
|
||||
public void testHiddenConstructorWithInlineClassParameters() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/HiddenConstructorWithInlineClassParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyField.kt")
|
||||
public void testPropertyField() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/PropertyField.kt");
|
||||
|
||||
Generated
+5
@@ -133,6 +133,11 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("HiddenConstructorWithInlineClassParameters.kt")
|
||||
public void testHiddenConstructorWithInlineClassParameters() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/HiddenConstructorWithInlineClassParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyField.kt")
|
||||
public void testPropertyField() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/PropertyField.kt");
|
||||
|
||||
Generated
+5
@@ -1789,6 +1789,11 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("HiddenConstructorWithInlineClassParameters.kt")
|
||||
public void testHiddenConstructorWithInlineClassParameters() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/HiddenConstructorWithInlineClassParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyField.kt")
|
||||
public void testPropertyField() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/PropertyField.kt");
|
||||
|
||||
+5
-4
@@ -17,13 +17,14 @@ import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
fun shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor: CallableMemberDescriptor): Boolean {
|
||||
if (descriptor !is ClassConstructorDescriptor) return false
|
||||
if (Visibilities.isPrivate(descriptor.visibility)) return false
|
||||
if (descriptor.constructedClass.isInline) return false
|
||||
val constructorDescriptor = descriptor as? ClassConstructorDescriptor ?: return false
|
||||
if (Visibilities.isPrivate(constructorDescriptor.visibility)) return false
|
||||
if (constructorDescriptor.constructedClass.isInline) return false
|
||||
if (DescriptorUtils.isSealedClass(constructorDescriptor.constructedClass)) return false
|
||||
|
||||
// TODO inner class in inline class
|
||||
|
||||
return descriptor.valueParameters.any { it.type.requiresFunctionNameMangling() }
|
||||
return constructorDescriptor.valueParameters.any { it.type.requiresFunctionNameMangling() }
|
||||
}
|
||||
|
||||
fun requiresFunctionNameMangling(valueParameterTypes: List<KotlinType>): Boolean {
|
||||
|
||||
+1
@@ -112,6 +112,7 @@ private class ClassClsStubBuilder(
|
||||
relevantFlags.add(INNER)
|
||||
relevantFlags.add(DATA)
|
||||
relevantFlags.add(MODALITY)
|
||||
relevantFlags.add(INLINE_CLASS)
|
||||
}
|
||||
val additionalModifiers = when (classKind) {
|
||||
ProtoBuf.Class.Kind.ENUM_CLASS -> listOf(KtTokens.ENUM_KEYWORD)
|
||||
|
||||
@@ -61,6 +61,7 @@ val EXTERNAL_FUN = createBooleanFlagToModifier(Flags.IS_EXTERNAL_FUNCTION, KtTok
|
||||
val EXTERNAL_PROPERTY = createBooleanFlagToModifier(Flags.IS_EXTERNAL_PROPERTY, KtTokens.EXTERNAL_KEYWORD)
|
||||
val EXTERNAL_CLASS = createBooleanFlagToModifier(Flags.IS_EXTERNAL_CLASS, KtTokens.EXTERNAL_KEYWORD)
|
||||
val INLINE = createBooleanFlagToModifier(Flags.IS_INLINE, KtTokens.INLINE_KEYWORD)
|
||||
val INLINE_CLASS = createBooleanFlagToModifier(Flags.IS_INLINE_CLASS, KtTokens.INLINE_KEYWORD)
|
||||
val TAILREC = createBooleanFlagToModifier(Flags.IS_TAILREC, KtTokens.TAILREC_KEYWORD)
|
||||
val SUSPEND = createBooleanFlagToModifier(Flags.IS_SUSPEND, KtTokens.SUSPEND_KEYWORD)
|
||||
|
||||
|
||||
Generated
+5
@@ -133,6 +133,11 @@ public class LoadJavaClsStubTestGenerated extends AbstractLoadJavaClsStubTest {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("HiddenConstructorWithInlineClassParameters.kt")
|
||||
public void testHiddenConstructorWithInlineClassParameters() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/HiddenConstructorWithInlineClassParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyField.kt")
|
||||
public void testPropertyField() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/PropertyField.kt");
|
||||
|
||||
@@ -133,6 +133,11 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("HiddenConstructorWithInlineClassParameters.kt")
|
||||
public void testHiddenConstructorWithInlineClassParameters() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/HiddenConstructorWithInlineClassParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyField.kt")
|
||||
public void testPropertyField() throws Exception {
|
||||
runTest("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/PropertyField.kt");
|
||||
|
||||
Reference in New Issue
Block a user