From 0632f90c53219cd6e1af789c06e90a90b13c86d1 Mon Sep 17 00:00:00 2001 From: svtk Date: Fri, 3 Feb 2012 20:35:20 +0400 Subject: [PATCH] KT-1193 Check enum entry supertype --- .../jet/lang/diagnostics/Errors.java | 3 + .../jet/lang/resolve/DeclarationsChecker.java | 64 ++++++++++++++----- .../tests/declarationChecks/kt1193.jet | 12 ++++ 3 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/declarationChecks/kt1193.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index eee0c5de5e1..99e65f700ff 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -151,6 +151,9 @@ public interface Errors { PsiElementOnlyDiagnosticFactory1 NOTHING_TO_OVERRIDE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "{0} overrides nothing", DescriptorRenderer.TEXT); PsiElementOnlyDiagnosticFactory3 VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT); + ParameterizedDiagnosticFactory1 ENUM_ENTRY_SHOULD_BE_INITIALIZED = ParameterizedDiagnosticFactory1.create(ERROR, "Missing delegation specifier ''{0}''", NAME); + ParameterizedDiagnosticFactory1 ENUM_ENTRY_ILLEGAL_TYPE = ParameterizedDiagnosticFactory1.create(ERROR, "The type constructor of enum entry should be ''{0}''", NAME); + PsiElementOnlyDiagnosticFactory1 UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME); PsiElementOnlyDiagnosticFactory1 UNINITIALIZED_PARAMETER = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Parameter ''{0}'' is uninitialized here", NAME); UnusedElementDiagnosticFactory UNUSED_VARIABLE = UnusedElementDiagnosticFactory.create(WARNING, "Variable ''{0}'' is never used", NAME); 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 ecd6e1058cb..18e2c8be3a5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -13,15 +13,18 @@ import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; /** * @author svtk @@ -57,7 +60,7 @@ public class DeclarationsChecker { for (Map.Entry entry : functions.entrySet()) { JetNamedFunction function = entry.getKey(); NamedFunctionDescriptor functionDescriptor = entry.getValue(); - + if (!context.completeAnalysisNeeded(function)) continue; checkFunction(function, functionDescriptor); checkModifiers(function.getModifierList()); @@ -67,7 +70,7 @@ public class DeclarationsChecker { for (Map.Entry entry : properties.entrySet()) { JetProperty property = entry.getKey(); PropertyDescriptor propertyDescriptor = entry.getValue(); - + if (!context.completeAnalysisNeeded(property)) continue; checkProperty(property, propertyDescriptor); checkModifiers(property.getModifierList()); @@ -78,6 +81,7 @@ public class DeclarationsChecker { private void checkClass(JetClass aClass, MutableClassDescriptor classDescriptor) { checkOpenMembers(aClass, classDescriptor); checkTraitModifiers(aClass); + checkEnum(aClass, classDescriptor); } private void checkTraitModifiers(JetClass aClass) { @@ -95,23 +99,23 @@ public class DeclarationsChecker { } } - + private void checkObject(JetObjectDeclaration objectDeclaration, MutableClassDescriptor classDescriptor) { checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), Sets.newHashSet(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD)); } private void checkOpenMembers(JetClass aClass, MutableClassDescriptor classDescriptor) { - for (CallableMemberDescriptor memberDescriptor : classDescriptor.getCallableMembers()) { - - JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, memberDescriptor); - if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { - JetModifierList modifierList = member.getModifierList(); - assert modifierList != null; - ASTNode openModifierNode = modifierList.getModifierNode(JetTokens.OPEN_KEYWORD); - context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member, openModifierNode, aClass)); - } + for (CallableMemberDescriptor memberDescriptor : classDescriptor.getCallableMembers()) { + + JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, memberDescriptor); + if (member != null && classDescriptor.getModality() == Modality.FINAL && member.hasModifier(JetTokens.OPEN_KEYWORD)) { + JetModifierList modifierList = member.getModifierList(); + assert modifierList != null; + ASTNode openModifierNode = modifierList.getModifierNode(JetTokens.OPEN_KEYWORD); + context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member, openModifierNode, aClass)); } - } + } + } private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); @@ -256,7 +260,7 @@ public class DeclarationsChecker { return; } if (hasAbstractModifier) { - context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(function, abstractNode, functionDescriptor)); + context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(function, abstractNode, functionDescriptor)); } if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null) { context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(function, nameIdentifier, functionDescriptor)); @@ -344,7 +348,7 @@ public class DeclarationsChecker { } } } - + @NotNull public static Map getNodesCorrespondingToModifiers(@NotNull JetModifierList modifierList, Collection possibleModifiers) { Map nodes = Maps.newHashMap(); @@ -355,4 +359,34 @@ public class DeclarationsChecker { } return nodes; } + + private void checkEnum(JetClass aClass, ClassDescriptor classDescriptor) { + if (classDescriptor.getKind() != ClassKind.ENUM_ENTRY) return; + + DeclarationDescriptor declaration = classDescriptor.getContainingDeclaration().getContainingDeclaration(); + assert declaration instanceof ClassDescriptor; + ClassDescriptor enumClass = (ClassDescriptor) declaration; + assert enumClass.getKind() == ClassKind.ENUM_CLASS; + + List delegationSpecifiers = aClass.getDelegationSpecifiers(); + ConstructorDescriptor constructor = enumClass.getUnsubstitutedPrimaryConstructor(); + assert constructor != null; + if (!constructor.getValueParameters().isEmpty() && delegationSpecifiers.isEmpty()) { + PsiElement nameIdentifier = aClass.getNameIdentifier(); + context.getTrace().report(ENUM_ENTRY_SHOULD_BE_INITIALIZED.on(nameIdentifier != null ? nameIdentifier : aClass, enumClass)); + } + + for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) { + JetTypeReference typeReference = delegationSpecifier.getTypeReference(); + if (typeReference != null) { + JetType type = context.getTrace().getBindingContext().get(TYPE, typeReference); + if (type != null) { + JetType enumType = enumClass.getDefaultType(); + if (!type.getConstructor().equals(enumType.getConstructor())) { + context.getTrace().report(ENUM_ENTRY_ILLEGAL_TYPE.on(typeReference, enumClass)); + } + } + } + } + } } diff --git a/compiler/testData/diagnostics/tests/declarationChecks/kt1193.jet b/compiler/testData/diagnostics/tests/declarationChecks/kt1193.jet new file mode 100644 index 00000000000..b2ba2797f86 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/kt1193.jet @@ -0,0 +1,12 @@ +//KT-1193 Check enum entry supertype + +package kt1193 + +open enum class MyEnum(val i: Int) { + A : MyEnum(12) + B //no error +} + +enum class MyChildEnum(i: Int, val s: String) : MyEnum(i) { + C : MyEnum(3) +}