Prohibit extending kotlin.Enum directly

#KT-7773 Fixed
This commit is contained in:
Dmitry Petrov
2017-05-24 16:17:28 +03:00
parent b9e45bcd54
commit 902d3af280
7 changed files with 62 additions and 3 deletions
@@ -49,9 +49,7 @@ import java.util.List;
import java.util.Map;
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
import static org.jetbrains.kotlin.diagnostics.Severity.INFO;
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
import static org.jetbrains.kotlin.diagnostics.Severity.*;
/**
* For error messages, see DefaultErrorMessages and IdeErrorMessages.
@@ -272,6 +270,8 @@ public interface Errors {
DiagnosticFactory0<KtNullableType> NULLABLE_SUPERTYPE = DiagnosticFactory0.create(ERROR, NULLABLE_TYPE);
DiagnosticFactory0<KtTypeReference> DYNAMIC_SUPERTYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtTypeReference, ClassDescriptor> CLASS_CANNOT_BE_EXTENDED_DIRECTLY = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtElement> MISSING_CONSTRUCTOR_KEYWORD = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> NON_PRIVATE_CONSTRUCTOR_IN_ENUM = DiagnosticFactory0.create(ERROR);
@@ -541,6 +541,7 @@ public class DefaultErrorMessages {
MAP.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects");
MAP.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class");
MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
MAP.put(CLASS_CANNOT_BE_EXTENDED_DIRECTLY, "Class {0} cannot be extended directly", NAME);
MAP.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain");
MAP.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects");
@@ -584,6 +584,9 @@ public class BodyResolver {
else if (ModalityKt.isFinalOrEnum(classDescriptor)) {
trace.report(FINAL_SUPERTYPE.on(typeReference));
}
else if (KotlinBuiltIns.isEnum(classDescriptor)) {
trace.report(CLASS_CANNOT_BE_EXTENDED_DIRECTLY.on(typeReference, classDescriptor));
}
}
}
}
@@ -0,0 +1,9 @@
class Test1 : <!CLASS_CANNOT_BE_EXTENDED_DIRECTLY!>Enum<Test1><!>("", 0)
class Outer {
class Test2 : <!CLASS_CANNOT_BE_EXTENDED_DIRECTLY!>Enum<Test2><!>("", 0)
}
fun outer() {
class Test3 : <!CLASS_CANNOT_BE_EXTENDED_DIRECTLY!>Enum<Test3><!>("", 0)
}
@@ -0,0 +1,36 @@
package
public fun outer(): kotlin.Unit
public final class Outer {
public constructor Outer()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final class Test2 : kotlin.Enum<Outer.Test2> {
public constructor Test2()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Outer.Test2): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<Outer.Test2!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public final class Test1 : kotlin.Enum<Test1> {
public constructor Test1()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Test1): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<Test1!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -7363,6 +7363,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("extendingEnumDirectly.kt")
public void testExtendingEnumDirectly() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/extendingEnumDirectly.kt");
doTest(fileName);
}
@TestMetadata("extensionNamedAsEnumEntry.kt")
public void testExtensionNamedAsEnumEntry() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/enum/extensionNamedAsEnumEntry.kt");
@@ -1040,6 +1040,10 @@ public abstract class KotlinBuiltIns {
return descriptor.getContainingDeclaration() == getAny();
}
public static boolean isEnum(@NotNull ClassDescriptor descriptor) {
return classFqNameEquals(descriptor, FQ_NAMES._enum);
}
public static boolean isCharSequence(@Nullable KotlinType type) {
return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.charSequence);
}