Disallow nested classes within inner & local classes

#KT-1174 In Progress
This commit is contained in:
Alexander Udalov
2012-12-03 21:18:46 +04:00
parent a0caa88adf
commit 0b51a6cae0
8 changed files with 54 additions and 4 deletions
@@ -522,6 +522,7 @@ public interface Errors {
DiagnosticFactory1<JetSimpleNameExpression, ClassifierDescriptor> NO_CLASS_OBJECT = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
SimpleDiagnosticFactory<PsiElement> NESTED_CLASS_NOT_ALLOWED = SimpleDiagnosticFactory.create(ERROR);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -230,6 +230,7 @@ public class DefaultErrorMessages {
MAP.put(NO_GENERICS_IN_SUPERTYPE_SPECIFIER, "Generic arguments of the base type must be specified");
MAP.put(INACCESSIBLE_OUTER_CLASS_EXPRESSION, "Expression is inaccessible from a nested class ''{0}'', use ''inner'' keyword to make the class inner", NAME);
MAP.put(NESTED_CLASS_NOT_ALLOWED, "Nested class is not allowed here, use ''inner'' keyword to make the class inner");
MAP.put(HAS_NEXT_MISSING, "hasNext() cannot be called on iterator() of type ''{0}''", RENDER_TYPE);
MAP.put(HAS_NEXT_FUNCTION_AMBIGUITY, "hasNext() is ambiguous for iterator() of type ''{0}''", RENDER_TYPE);
@@ -21,10 +21,12 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetModifierList;
import org.jetbrains.jet.lang.psi.JetModifierListOwner;
import org.jetbrains.jet.lexer.JetKeywordToken;
@@ -103,6 +105,14 @@ public class ModifiersChecker {
checkIllegalInThisContextModifiers(modifierList, Collections.singletonList(INNER_KEYWORD));
}
}
else {
if (modifierListOwner instanceof JetClass && isIllegalNestedClass(descriptor)) {
PsiElement name = ((JetClass) modifierListOwner).getNameIdentifier();
if (name != null) {
trace.report(Errors.NESTED_CLASS_NOT_ALLOWED.on(name));
}
}
}
}
private static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) {
@@ -114,6 +124,14 @@ public class ModifiersChecker {
return ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.TRAIT;
}
private static boolean isIllegalNestedClass(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ClassDescriptor)) return false;
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) return false;
ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
return containingClass.isInner() || containingClass.getContainingDeclaration() instanceof FunctionDescriptor;
}
private void checkCompatibility(@Nullable JetModifierList modifierList, Collection<JetKeywordToken> availableModifiers, Collection<JetToken>... availableCombinations) {
if (modifierList == null) return;
Collection<JetKeywordToken> presentModifiers = Sets.newLinkedHashSet();