diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index 4f8d45290b1..6bea8886ebd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -36,6 +36,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE_PARAMETER; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.classCanHaveAbstractMembers; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.classCanHaveOpenMembers; public class DeclarationsChecker { @NotNull @@ -337,10 +338,12 @@ public class DeclarationsChecker { } private void checkOpenMembers(ClassDescriptorWithResolutionScopes classDescriptor) { + if (classCanHaveOpenMembers(classDescriptor)) return; + for (CallableMemberDescriptor memberDescriptor : classDescriptor.getDeclaredCallableMembers()) { if (memberDescriptor.getKind() != CallableMemberDescriptor.Kind.DECLARATION) continue; JetNamedDeclaration member = (JetNamedDeclaration) DescriptorToSourceUtils.descriptorToDeclaration(memberDescriptor); - if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { + if (member != null && member.hasModifier(JetTokens.OPEN_KEYWORD)) { trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member)); } } diff --git a/compiler/testData/diagnostics/tests/enum/openMemberInEnum.kt b/compiler/testData/diagnostics/tests/enum/openMemberInEnum.kt new file mode 100644 index 00000000000..f9a9e4b9ee2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/openMemberInEnum.kt @@ -0,0 +1,17 @@ +enum class EnumWithOpenMembers { + E1 { + override fun foo() = 1 + override val bar: String = "a" + } + + E2 { + override fun f() = 3 + override val b = 4 + } + + open fun foo() = 1 + open val bar: String = "" + + fun f() = 2 + val b = 3 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/enum/openMemberInEnum.txt b/compiler/testData/diagnostics/tests/enum/openMemberInEnum.txt new file mode 100644 index 00000000000..6a5818cc269 --- /dev/null +++ b/compiler/testData/diagnostics/tests/enum/openMemberInEnum.txt @@ -0,0 +1,70 @@ +package + +internal final enum class EnumWithOpenMembers : kotlin.Enum { + private constructor EnumWithOpenMembers() + internal final val b: kotlin.Int = 3 + internal open val bar: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun f(): kotlin.Int + internal open fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public enum entry E1 : EnumWithOpenMembers { + private constructor E1() + internal final override /*1*/ /*fake_override*/ val b: kotlin.Int + internal open override /*1*/ val bar: kotlin.String = "a" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun f(): kotlin.Int + internal open override /*1*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumWithOpenMembers.E1 { + private constructor () + internal final override /*1*/ /*fake_override*/ val b: kotlin.Int + internal open override /*1*/ /*fake_override*/ val bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun f(): kotlin.Int + internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + public enum entry E2 : EnumWithOpenMembers { + private constructor E2() + internal open override /*1*/ val b: kotlin.Int = 4 + internal open override /*1*/ /*fake_override*/ val bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open override /*1*/ fun f(): kotlin.Int + internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public class object : EnumWithOpenMembers.E2 { + private constructor () + internal open override /*1*/ /*fake_override*/ val b: kotlin.Int + internal open override /*1*/ /*fake_override*/ val bar: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open override /*1*/ /*fake_override*/ fun f(): kotlin.Int + internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): EnumWithOpenMembers + public final /*synthesized*/ fun values(): kotlin.Array +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index c0d5da5ecb5..1552d2bd8b2 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3889,6 +3889,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("openMemberInEnum.kt") + public void testOpenMemberInEnum() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/openMemberInEnum.kt"); + doTest(fileName); + } + @TestMetadata("starImportNestedClassAndEntries.kt") public void testStarImportNestedClassAndEntries() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/starImportNestedClassAndEntries.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 7a313d5d16e..34c4a397460 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -405,4 +405,8 @@ public class DescriptorUtils { public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) { return classDescriptor.getModality() == Modality.ABSTRACT || classDescriptor.getKind() == ClassKind.ENUM_CLASS; } + + public static boolean classCanHaveOpenMembers(@NotNull ClassDescriptor classDescriptor) { + return classDescriptor.getModality() != Modality.FINAL || classDescriptor.getKind() == ClassKind.ENUM_CLASS; + } }