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
This commit is contained in:
Alexander Udalov
2021-12-16 00:19:07 +01:00
parent fc2c0eea27
commit b3820564b0
8 changed files with 82 additions and 20 deletions
@@ -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 {
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
enum class E {
X {
override fun a() {}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
enum class Enum1 {
BLACK, WHITE
}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
interface Context
enum class Result {
@@ -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
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class `:)` {
lateinit val f: String
}
@@ -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) {
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// STRIP_METADATA
interface Context