From b3820564b0c3aa0075a5124510b0156ef1b2de1e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 16 Dec 2021 00:19:07 +0100 Subject: [PATCH] Kapt: never generate enums as final Behavior differs between JVM and JVM_IR backends here because in JVM, the class descriptor comes from the frontend, and its modality for enum is never final. For JVM IR, the class descriptor is based on IrClass, whose modality is sometimes final for enum, presumably because it's easier for backends (see `ClassGenerator.getEffectiveModality`). #KT-49682 --- .../stubs/ClassFileToSourceStubConverter.kt | 26 +++++--- .../testData/converter/abstractEnum.kt | 2 - .../testData/converter/enums.kt | 2 - .../testData/converter/inheritanceSimple.kt | 2 - .../testData/converter/invalidFieldName.kt | 4 +- .../testData/converter/strangeIdentifiers.kt | 2 - .../converter/strangeIdentifiers_ir.txt | 63 +++++++++++++++++++ .../testData/converter/stripMetadata.kt | 1 - 8 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers_ir.txt diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index b320d5c3b88..f25e1f73113 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -50,13 +50,16 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.ArrayFqNames import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DelegatingBindingTrace -import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall -import org.jetbrains.kotlin.resolve.calls.util.getType import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument +import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.getType import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator -import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny +import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.ErrorUtils @@ -646,15 +649,22 @@ class ClassFileToSourceStubConverter(val kaptContext: KaptContextForStubGenerati return doesInnerClassNameConflictWithOuter(clazz, containingClassForOuterClass) } - private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean) = when { - (descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE -> { + private fun getClassAccessFlags(clazz: ClassNode, descriptor: DeclarationDescriptor, isInner: Boolean, isNested: Boolean): Int { + if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) { // Classes inside interfaces should always be public and static. // See com.sun.tools.javac.comp.Enter.visitClassDef for more information. - (clazz.access or Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) and + return (clazz.access or Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC) and Opcodes.ACC_PRIVATE.inv() and Opcodes.ACC_PROTECTED.inv() // Remove private and protected modifiers } - !isInner && isNested -> clazz.access or Opcodes.ACC_STATIC - else -> clazz.access + var access = clazz.access + if ((descriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS) { + // Enums are final in the bytecode, but "final enum" is not allowed in Java. + access = access and Opcodes.ACC_FINAL.inv() + } + if (!isInner && isNested) { + access = access or Opcodes.ACC_STATIC + } + return access } private fun getClassName(clazz: ClassNode, descriptor: DeclarationDescriptor, isDefaultImpls: Boolean, packageFqName: String): String { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/abstractEnum.kt b/plugins/kapt3/kapt3-compiler/testData/converter/abstractEnum.kt index bb25568606f..262d2b717b1 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/abstractEnum.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/abstractEnum.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR - enum class E { X { override fun a() {} diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/enums.kt b/plugins/kapt3/kapt3-compiler/testData/converter/enums.kt index 0e226c30e85..494cb4c3b0f 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/enums.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/enums.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR - enum class Enum1 { BLACK, WHITE } diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt b/plugins/kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt index 30c4e5c5616..7a8d995e4b1 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/inheritanceSimple.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR - interface Context enum class Result { diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt b/plugins/kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt index 6d2b9364697..00144698f89 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/invalidFieldName.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR - enum class Color { BLACK, `WHI-TE` } @@ -7,5 +5,5 @@ enum class Color { @Anno(Color.`WHI-TE`) annotation class Anno(val color: Color) -// EXPECTED_ERROR(kotlin:7:1) an enum annotation value must be an enum constant +// EXPECTED_ERROR(kotlin:5:1) an enum annotation value must be an enum constant // EXPECTED_ERROR(other:-1:-1) 'WHI-TE' is an invalid Java enum value name diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt b/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt index 444e65c9b9b..fc623ea4356 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR - class `:)` { lateinit val f: String } diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers_ir.txt b/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers_ir.txt new file mode 100644 index 00000000000..570775834a9 --- /dev/null +++ b/plugins/kapt3/kapt3-compiler/testData/converter/strangeIdentifiers_ir.txt @@ -0,0 +1,63 @@ +import java.lang.System; + +@kotlin.Metadata() +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface Anno { + + public abstract StrangeEnum size(); + + public abstract java.lang.String name(); +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public enum StrangeEnum { + /*public static final*/ InvalidFieldName /* = new StrangeEnum() */; + @org.jetbrains.annotations.NotNull() + private final java.lang.String size = null; + + StrangeEnum(java.lang.String size) { + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getSize() { + return null; + } +} + +//////////////////// + + +import java.lang.System; + +@kotlin.Metadata() +public final class Test { + public final java.lang.String simpleName = null; + + public Test() { + super(); + } + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getSimpleName() { + return null; + } + + public final void simpleFun() { + } + + @Anno(size = StrangeEnum.InvalidFieldName, name = "Woofwoof") + public final void simpleFun2(@org.jetbrains.annotations.NotNull() + java.lang.String a, @org.jetbrains.annotations.NotNull() + java.lang.String b) { + } + + public final void strangeFun4(@org.jetbrains.annotations.NotNull() + java.lang.String a, @org.jetbrains.annotations.NotNull() + java.lang.String p1_949560896) { + } +} diff --git a/plugins/kapt3/kapt3-compiler/testData/converter/stripMetadata.kt b/plugins/kapt3/kapt3-compiler/testData/converter/stripMetadata.kt index cbe13881c46..b29dd5a70bc 100644 --- a/plugins/kapt3/kapt3-compiler/testData/converter/stripMetadata.kt +++ b/plugins/kapt3/kapt3-compiler/testData/converter/stripMetadata.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // STRIP_METADATA interface Context