diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java index ce47d93a1eb..3ecc3436798 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java @@ -45,5 +45,5 @@ public interface ClassDescriptor extends ClassifierDescriptor { boolean isObject(); @NotNull - ClassModifiers getClassModifiers(); + ClassModifiers getModifiers(); } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java index 08a3aa0c600..26d24355a0d 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorImpl.java @@ -118,7 +118,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl @Override @NotNull - public ClassModifiers getClassModifiers() { + public ClassModifiers getModifiers() { return ClassModifiers.DEFAULT_MODIFIERS; } } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/ClassModifiers.java b/idea/src/org/jetbrains/jet/lang/descriptors/ClassModifiers.java index 3fe650310d7..a7012d36788 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/ClassModifiers.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/ClassModifiers.java @@ -4,15 +4,17 @@ package org.jetbrains.jet.lang.descriptors; * @author svtk */ public class ClassModifiers extends Modifiers { - public static final ClassModifiers DEFAULT_MODIFIERS = new ClassModifiers(false, false, false); + public static final ClassModifiers DEFAULT_MODIFIERS = new ClassModifiers(false, false, false, false); private boolean open; private boolean trait; + private boolean isEnum; - public ClassModifiers(boolean anAbstract, boolean open, boolean trait) { + public ClassModifiers(boolean anAbstract, boolean open, boolean trait, boolean isEnum) { super(anAbstract); this.open = open; this.trait = trait; + this.isEnum = isEnum; } public boolean isOpen() { @@ -22,6 +24,8 @@ public class ClassModifiers extends Modifiers { public boolean isTrait() { return trait; } - - + + public boolean isEnum() { + return isEnum; + } } diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java index 0bd3c58ca7c..f19a68ec4cb 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/LazySubstitutingClassDescriptor.java @@ -141,8 +141,8 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor { @Override @NotNull - public ClassModifiers getClassModifiers() { - return original.getClassModifiers(); + public ClassModifiers getModifiers() { + return original.getModifiers(); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 2cd0326c3ac..2b291eafec2 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -254,7 +254,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override @NotNull - public ClassModifiers getClassModifiers() { + public ClassModifiers getModifiers() { return classModifiers; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 414bd446f69..c61b94ede24 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -561,10 +561,12 @@ public class ClassDescriptorResolver { if (modifierList == null) return ClassModifiers.DEFAULT_MODIFIERS; boolean abstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD); boolean traitModifier = modifierList.hasModifier(JetTokens.TRAIT_KEYWORD); + boolean enumModifier = modifierList.hasModifier(JetTokens.ENUM_KEYWORD); return new ClassModifiers( abstractModifier || traitModifier, modifierList.hasModifier(JetTokens.OPEN_KEYWORD) || abstractModifier || traitModifier, - traitModifier + traitModifier, + enumModifier ); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 32489e59622..6e5f0bca14b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -487,7 +487,7 @@ public class TopDownAnalyzer { private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) { if (!klass.hasPrimaryConstructor()) return; - if (classDescriptor.getClassModifiers().isTrait()) { + if (classDescriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor"); } @@ -509,7 +509,7 @@ public class TopDownAnalyzer { } private void processSecondaryConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { - if (classDescriptor.getClassModifiers().isTrait()) { + if (classDescriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(constructor.getNameNode(), "A trait may not have a constructor"); } ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolveSecondaryConstructorDescriptor( @@ -632,7 +632,7 @@ public class TopDownAnalyzer { @Override public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { - if (descriptor.getClassModifiers().isTrait()) { + if (descriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(specifier.getNode(), "Traits can not use delegation"); } JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); @@ -653,7 +653,7 @@ public class TopDownAnalyzer { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); - if (descriptor.getClassModifiers().isTrait()) { + if (descriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(node, "Traits can not initialize supertypes"); } JetTypeReference typeReference = call.getTypeReference(); @@ -664,7 +664,7 @@ public class TopDownAnalyzer { recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { - if (classDescriptor.getClassModifiers().isTrait()) { + if (classDescriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(node, "A trait may not have a constructor"); } } @@ -673,7 +673,7 @@ public class TopDownAnalyzer { recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference)); } } - else if (!descriptor.getClassModifiers().isTrait()) { + else if (!descriptor.getModifiers().isTrait()) { JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference); recordSupertype(typeReference, supertype); @@ -692,8 +692,8 @@ public class TopDownAnalyzer { if (supertype != null) { ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { - if (!descriptor.getClassModifiers().isTrait()) { - if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getClassModifiers().isTrait()) { + if (!descriptor.getModifiers().isTrait()) { + if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && !classDescriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here"); } } @@ -735,7 +735,7 @@ public class TopDownAnalyzer { ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { - if (!classDescriptor.getClassModifiers().isTrait()) { + if (!classDescriptor.getModifiers().isTrait()) { if (classAppeared) { trace.getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list"); } @@ -987,7 +987,7 @@ public class TopDownAnalyzer { "Global property can not be abstract"); return; } - if (!classDescriptor.getClassModifiers().isAbstract()) { + if (!classDescriptor.getModifiers().isAbstract()) { trace.getErrorHandler().genericError(property.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName()); return; @@ -1008,7 +1008,7 @@ public class TopDownAnalyzer { if (initializer == null && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) { if (classDescriptor == null || (getter != null && getter.getBodyExpression() != null) || (setter != null && setter.getBodyExpression() != null)) { trace.getErrorHandler().genericError(nameNode, "Property must be initialized"); - } else if (!classDescriptor.getClassModifiers().isTrait()) { + } else if (!classDescriptor.getModifiers().isTrait()) { trace.getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract"); } } @@ -1022,22 +1022,34 @@ public class TopDownAnalyzer { protected void checkFunction(JetNamedFunction function, FunctionDescriptor functionDescriptor, DeclarationDescriptor containingDescriptor) { PsiElement nameIdentifier = function.getNameIdentifier(); + boolean isAbstract = functionDescriptor.getModifiers().isAbstract(); if (containingDescriptor instanceof ClassDescriptor) { ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor; - if (functionDescriptor.getModifiers().isAbstract() && !classDescriptor.getClassModifiers().isAbstract()) { + boolean inTrait = classDescriptor.getModifiers().isTrait(); + boolean inEnum = classDescriptor.getModifiers().isEnum(); + boolean inAbstractClass = classDescriptor.getModifiers().isAbstract(); + if (isAbstract && !inAbstractClass && !inTrait && !inEnum) { trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), "Abstract method " + function.getName() + " in non-abstract class " + classDescriptor.getName()); } - if (function.getBodyExpression() == null && !functionDescriptor.getModifiers().isAbstract() && nameIdentifier != null) { + if (isAbstract && inTrait) { + trace.getErrorHandler().genericWarning(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), + "Abstract modifier is not necessary in traits"); + } + if (function.getBodyExpression() != null && isAbstract) { + trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), + "Method " + function.getName() + " with body can not be abstract"); + } + if (function.getBodyExpression() == null && !isAbstract && !inTrait && nameIdentifier != null) { trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Method " + function.getName() + " without body must be abstract"); } return; } - if (functionDescriptor.getModifiers().isAbstract()) { + if (isAbstract) { trace.getErrorHandler().genericError(function.getModifierList().getModifierNode(JetTokens.ABSTRACT_KEYWORD), "Global function " + function.getName() + " can not be abstract"); } - if (function.getBodyExpression() == null && !functionDescriptor.getModifiers().isAbstract() && nameIdentifier != null) { + if (function.getBodyExpression() == null && !isAbstract && nameIdentifier != null) { trace.getErrorHandler().genericError(nameIdentifier.getNode(), "Global function " + function.getName() + " must have body"); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 98bca6a932a..f7e2e41d497 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -101,7 +101,7 @@ public class CallResolver { @Override public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { if (descriptor instanceof ConstructorDescriptor) { - ClassModifiers modifiers = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getClassModifiers(); + ClassModifiers modifiers = ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModifiers(); if (modifiers.isAbstract()) { tracing.reportOverallResolutionError(trace, "Can not create an instance of an abstract class"); return false; diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java index 1900c6af2c5..3ddaa4f2c81 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassDescriptor.java @@ -21,9 +21,6 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements private JetType classObjectType; private final WritableFunctionGroup constructors = new WritableFunctionGroup(""); private ClassModifiers modifiers; -// private boolean isAbstract; -// private boolean isOpen; -// private boolean isTrait; public JavaClassDescriptor(DeclarationDescriptor containingDeclaration) { super(containingDeclaration); @@ -33,11 +30,8 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements this.typeConstructor = typeConstructor; } - public void setModifiers(boolean isAbstract, boolean isOpen, boolean isTrait) { - this.modifiers = new ClassModifiers(isAbstract, isOpen, isTrait); -// this.isAbstract = isAbstract; -// this.isOpen = isOpen; -// this.isTrait = isTrait; + public void setModifiers(boolean isAbstract, boolean isOpen, boolean isTrait, boolean isEnum) { + this.modifiers = new ClassModifiers(isAbstract, isOpen, isTrait, isEnum); } public void setUnsubstitutedMemberScope(JavaClassMembersScope memberScope) { @@ -131,24 +125,9 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements return false; } -// @Override -// public boolean isAbstract() { -// return isAbstract; -// } -// -// @Override -// public boolean isOpen() { -// return isOpen; -// } -// -// @Override -// public boolean isTrait() { -// return isTrait; -// } - @Override @NotNull - public ClassModifiers getClassModifiers() { + public ClassModifiers getModifiers() { return modifiers; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index fd320d03adc..e5b388ee501 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -109,7 +109,8 @@ public class JavaDescriptorResolver { classDescriptor.setModifiers( psiClass.hasModifierProperty(PsiModifier.ABSTRACT), !psiClass.hasModifierProperty(PsiModifier.FINAL), - psiClass.isInterface() + psiClass.isInterface(), + psiClass.isEnum() ); classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); diff --git a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 33f00dd4a3e..4d00ec6281a 100644 --- a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -251,7 +251,7 @@ public class DescriptorRenderer { @Override public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) { - String keyword = descriptor.getClassModifiers().isTrait() ? "trait class" : "class"; + String keyword = descriptor.getModifiers().isTrait() ? "trait class" : "class"; renderClassDescriptor(descriptor, builder, keyword); return super.visitClassDescriptor(descriptor, builder); } diff --git a/idea/testData/checker/Abstract.jet b/idea/testData/checker/Abstract.jet index 238c0e32c09..e91ffe9735d 100644 --- a/idea/testData/checker/Abstract.jet +++ b/idea/testData/checker/Abstract.jet @@ -1,5 +1,33 @@ namespace abstract +class MyClass() { + fun f() + fun g() {} + abstract fun h() + abstract fun j() {} +} + +abstract class MyAbstractClass() { + fun f() + fun g() {} + abstract fun h() + abstract fun j() {} +} + +trait class MyTrait { + fun f() + fun g() {} + abstract fun h() + abstract fun j() {} +} + +enum class MyEnum { + fun f() + fun g() {} + abstract fun h() + abstract fun j() {} +} + class A1() { fun foo(): Int abstract fun f(): Int @@ -65,4 +93,4 @@ abstract class B3(i: Int) { fun foo(a: B3) { val a = B3() val b = B1(2, "s") -} +} \ No newline at end of file