Modifiers checks were moved to DeclarationsChecker; added 'open' modifier checks

This commit is contained in:
svtk
2011-09-29 13:34:41 +04:00
parent 7b2c5132f7
commit 225913126b
24 changed files with 460 additions and 334 deletions
@@ -27,8 +27,8 @@ public abstract class DiagnosticFactoryWithPsiElement1<T extends PsiElement, A>
} }
@NotNull @NotNull
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A argument) { public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A argument) {
return on(element, element.getTextRange(), argument); return on(elementToMark, elementToMark.getTextRange(), argument);
} }
@NotNull @NotNull
@@ -31,8 +31,8 @@ public abstract class DiagnosticFactoryWithPsiElement2<T extends PsiElement, A,
} }
@NotNull @NotNull
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A a, @NotNull B b) { public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A a, @NotNull B b) {
return on(element, element.getNode(), a, b); return on(elementToMark, elementToMark.getNode(), a, b);
} }
@NotNull @NotNull
@@ -34,8 +34,8 @@ public abstract class DiagnosticFactoryWithPsiElement3<T extends PsiElement, A,
} }
@NotNull @NotNull
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A a, @NotNull B b, @NotNull C c) { public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A a, @NotNull B b, @NotNull C c) {
return on(element, element, a, b, c); return on(elementToMark, elementToMark, a, b, c);
} }
@NotNull @NotNull
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.diagnostics; package org.jetbrains.jet.lang.diagnostics;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetKeywordToken;
@@ -11,4 +12,5 @@ public interface DiagnosticParameters {
DiagnosticParameter<JetKeywordToken> MODIFIER = new DiagnosticParameterImpl<JetKeywordToken>("MODIFIER"); DiagnosticParameter<JetKeywordToken> MODIFIER = new DiagnosticParameterImpl<JetKeywordToken>("MODIFIER");
DiagnosticParameter<JetClass> CLASS = new DiagnosticParameterImpl<JetClass>("CLASS"); DiagnosticParameter<JetClass> CLASS = new DiagnosticParameterImpl<JetClass>("CLASS");
DiagnosticParameter<JetType> TYPE = new DiagnosticParameterImpl<JetType>("TYPE"); DiagnosticParameter<JetType> TYPE = new DiagnosticParameterImpl<JetType>("TYPE");
DiagnosticParameter<JetProperty> PROPERTY = new DiagnosticParameterImpl<JetProperty>("TYPE");
} }
@@ -59,6 +59,7 @@ public interface Errors {
return sb.toString(); return sb.toString();
} }
}; };
ParameterizedDiagnosticFactory1<JetKeywordToken> ILLEGAL_MODIFIER = ParameterizedDiagnosticFactory1.create(ERROR, "Illegal modifier ''{0}''");
PsiElementOnlyDiagnosticFactory2<JetModifierList, JetKeywordToken, JetKeywordToken> REDUNDANT_MODIFIER = new PsiElementOnlyDiagnosticFactory2<JetModifierList, JetKeywordToken, JetKeywordToken>(Severity.WARNING, "Modifier {0} is redundant because {1} is present") { PsiElementOnlyDiagnosticFactory2<JetModifierList, JetKeywordToken, JetKeywordToken> REDUNDANT_MODIFIER = new PsiElementOnlyDiagnosticFactory2<JetModifierList, JetKeywordToken, JetKeywordToken>(Severity.WARNING, "Modifier {0} is redundant because {1} is present") {
@NotNull @NotNull
@@ -67,6 +68,8 @@ public interface Errors {
return super.on(elementToBlame, nodeToMark, redundantModifier, presentModifier).add(DiagnosticParameters.MODIFIER, redundantModifier); return super.on(elementToBlame, nodeToMark, redundantModifier, presentModifier).add(DiagnosticParameters.MODIFIER, redundantModifier);
} }
}; };
DiagnosticWithParameterFactory<JetModifierList, JetKeywordToken> REDUNDANT_MODIFIER_IN_TRAIT = DiagnosticWithParameterFactory.create(WARNING, "Modifier ''{0}'' is redundant in trait", DiagnosticParameters.MODIFIER);
SimplePsiElementOnlyDiagnosticFactory<JetClass> TRAIT_CAN_NOT_BE_FINAL = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "Trait can not be final");
SimpleDiagnosticFactory SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES = SimpleDiagnosticFactory.create(ERROR, "Safe calls are not allowed on namespaces"); SimpleDiagnosticFactory SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES = SimpleDiagnosticFactory.create(ERROR, "Safe calls are not allowed on namespaces");
SimpleDiagnosticFactory TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM = SimpleDiagnosticFactory.create(ERROR, "Type checking has run into a recursive problem"); // TODO: message SimpleDiagnosticFactory TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM = SimpleDiagnosticFactory.create(ERROR, "Type checking has run into a recursive problem"); // TODO: message
SimpleDiagnosticFactory RETURN_NOT_ALLOWED = SimpleDiagnosticFactory.create(ERROR, "'return' is not allowed here"); SimpleDiagnosticFactory RETURN_NOT_ALLOWED = SimpleDiagnosticFactory.create(ERROR, "'return' is not allowed here");
@@ -116,6 +119,9 @@ public interface Errors {
SimplePsiElementOnlyDiagnosticFactory<JetModifierListOwner> NON_MEMBER_ABSTRACT_ACCESSOR = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "This property is not a class or trait member and thus cannot have abstract accessors"); // TODO : Better message SimplePsiElementOnlyDiagnosticFactory<JetModifierListOwner> NON_MEMBER_ABSTRACT_ACCESSOR = SimplePsiElementOnlyDiagnosticFactory.create(ERROR, "This property is not a class or trait member and thus cannot have abstract accessors"); // TODO : Better message
PsiElementOnlyDiagnosticFactory1<JetFunctionOrPropertyAccessor, FunctionDescriptor> NON_MEMBER_FUNCTION_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function {0} must have a body"); PsiElementOnlyDiagnosticFactory1<JetFunctionOrPropertyAccessor, FunctionDescriptor> NON_MEMBER_FUNCTION_NO_BODY = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function {0} must have a body");
DiagnosticWithParameterFactory<JetNamedDeclaration, JetClass> NON_FINAL_MEMBER_IN_FINAL_CLASS = DiagnosticWithParameterFactory.create(ERROR, "Non final member in a final class", DiagnosticParameters.CLASS);
DiagnosticWithParameterFactory<JetPropertyAccessor, JetProperty> NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY = DiagnosticWithParameterFactory.create(ERROR, "Non final accessor of a final property", DiagnosticParameters.PROPERTY);
SimpleDiagnosticFactory PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT = SimpleDiagnosticFactory.create(ERROR, "Projections are not allowed on type arguments of functions and properties"); // TODO : better positioning SimpleDiagnosticFactory PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT = SimpleDiagnosticFactory.create(ERROR, "Projections are not allowed on type arguments of functions and properties"); // TODO : better positioning
SimpleDiagnosticFactory SUPERTYPE_NOT_INITIALIZED = SimpleDiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here"); SimpleDiagnosticFactory SUPERTYPE_NOT_INITIALIZED = SimpleDiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here");
@@ -27,12 +27,12 @@ public class ParameterizedDiagnosticFactory1<A> extends DiagnosticFactoryWithPsi
} }
@NotNull @NotNull
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A argument) { public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange rangeToMark, @NotNull A argument) {
return new GenericDiagnostic(this, severity, makeMessage(argument), psiFile, range); return new GenericDiagnostic(this, severity, makeMessage(argument), psiFile, rangeToMark);
} }
@NotNull @NotNull
public Diagnostic on(@NotNull ASTNode node, @NotNull A argument) { public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A argument) {
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), argument); return on(DiagnosticUtils.getContainingFile(nodeToMark), nodeToMark.getTextRange(), argument);
} }
} }
@@ -27,13 +27,13 @@ public class ParameterizedDiagnosticFactory2<A, B> extends DiagnosticFactoryWith
} }
@NotNull @NotNull
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A a, @NotNull B b) { public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange rangeToMark, @NotNull A a, @NotNull B b) {
return new GenericDiagnostic(this, severity, makeMessage(a, b), psiFile, range); return new GenericDiagnostic(this, severity, makeMessage(a, b), psiFile, rangeToMark);
} }
@NotNull @NotNull
public Diagnostic on(@NotNull ASTNode node, @NotNull A a, @NotNull B b) { public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A a, @NotNull B b) {
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), a, b); return on(DiagnosticUtils.getContainingFile(nodeToMark), nodeToMark.getTextRange(), a, b);
} }
} }
@@ -27,12 +27,12 @@ public class ParameterizedDiagnosticFactory3<A, B, C> extends DiagnosticFactoryW
} }
@NotNull @NotNull
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A a, @NotNull B b, @NotNull C c) { public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange rangeToMark, @NotNull A a, @NotNull B b, @NotNull C c) {
return new GenericDiagnostic(this, severity, makeMessage(a, b, c), psiFile, range); return new GenericDiagnostic(this, severity, makeMessage(a, b, c), psiFile, rangeToMark);
} }
@NotNull @NotNull
public Diagnostic on(@NotNull ASTNode node, @NotNull A a, @NotNull B b, @NotNull C c) { public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A a, @NotNull B b, @NotNull C c) {
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), a, b, c); return on(DiagnosticUtils.getContainingFile(nodeToMark), nodeToMark.getTextRange(), a, b, c);
} }
} }
@@ -3,10 +3,8 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -18,14 +16,17 @@ import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.slicedmap.WritableSlice; import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.*; import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
/** /**
* @author abreslav * @author abreslav
*/ */
public class BodyResolver { public class BodyResolver {
private final TopDownAnalysisContext context; private final TopDownAnalysisContext context;
@@ -43,7 +44,6 @@ public class BodyResolver {
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression;
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
if (!BodyResolver.this.context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) { if (!BodyResolver.this.context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) {
// BodyResolver.this.context.getTrace().getErrorHandler().genericError(expression.getNode(), "This property does not have a backing field");
BodyResolver.this.context.getTrace().report(NO_BACKING_FIELD.on(expression)); BodyResolver.this.context.getTrace().report(NO_BACKING_FIELD.on(expression));
} }
} }
@@ -68,7 +68,6 @@ public class BodyResolver {
public void resolveBehaviorDeclarationBodies() { public void resolveBehaviorDeclarationBodies() {
// bindOverrides();
resolveDelegationSpecifierLists(); resolveDelegationSpecifierLists();
resolveClassAnnotations(); resolveClassAnnotations();
@@ -79,30 +78,9 @@ public class BodyResolver {
resolveSecondaryConstructorBodies(); resolveSecondaryConstructorBodies();
resolveFunctionBodies(); resolveFunctionBodies();
checkIfPrimaryConstructorIsNecessary();
// checkOverrides();
} }
private void checkIfPrimaryConstructorIsNecessary() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
PsiElement nameIdentifier = jetClass.getNameIdentifier();
if (nameIdentifier != null) {
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(),
// "This class must have a primary constructor, because property " + propertyDescriptor.getName() + " has a backing field");
context.getTrace().report(PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY.on(jetClass, nameIdentifier, propertyDescriptor));
}
break;
}
}
}
}
}
private void resolveDelegationSpecifierLists() { private void resolveDelegationSpecifierLists() {
// TODO : Make sure the same thing is not initialized twice // TODO : Make sure the same thing is not initialized twice
@@ -117,8 +95,8 @@ public class BodyResolver {
private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
final JetScope scopeForConstructor = primaryConstructor == null final JetScope scopeForConstructor = primaryConstructor == null
? null ? null
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true); : getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap(); final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
@@ -131,7 +109,6 @@ public class BodyResolver {
@Override @Override
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
if (descriptor.getKind() == ClassKind.TRAIT) { if (descriptor.getKind() == ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Traits cannot use delegation");
context.getTrace().report(DELEGATION_IN_TRAIT.on(specifier)); context.getTrace().report(DELEGATION_IN_TRAIT.on(specifier));
} }
JetType supertype = context.getTrace().getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference()); JetType supertype = context.getTrace().getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
@@ -162,7 +139,6 @@ public class BodyResolver {
JetValueArgumentList valueArgumentList = call.getValueArgumentList(); JetValueArgumentList valueArgumentList = call.getValueArgumentList();
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
if (descriptor.getKind() == ClassKind.TRAIT) { if (descriptor.getKind() == ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericError(node, "Traits cannot initialize supertypes");
context.getTrace().report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(node)); context.getTrace().report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(node));
} }
JetTypeReference typeReference = call.getTypeReference(); JetTypeReference typeReference = call.getTypeReference();
@@ -174,7 +150,6 @@ public class BodyResolver {
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) { if (classDescriptor != null) {
if (classDescriptor.getKind() == ClassKind.TRAIT) { if (classDescriptor.getKind() == ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericError(node, "A trait may not have a constructor");
context.getTrace().report(CONSTRUCTOR_IN_TRAIT.on(node)); context.getTrace().report(CONSTRUCTOR_IN_TRAIT.on(node));
} }
} }
@@ -188,8 +163,6 @@ public class BodyResolver {
recordSupertype(typeReference, supertype); recordSupertype(typeReference, supertype);
assert valueArgumentList != null; assert valueArgumentList != null;
// context.getTrace().getErrorHandler().genericError(valueArgumentList.getNode(),
// "Class " + JetPsiUtil.safeName(jetClass.getName()) + " must have a constructor in order to be able to initialize supertypes");
context.getTrace().report(PRIMARY_CONSTRUCTOR_MISSING_SUPER_CONSTRUCTOR_CALL.on(valueArgumentList, jetClass)); context.getTrace().report(PRIMARY_CONSTRUCTOR_MISSING_SUPER_CONSTRUCTOR_CALL.on(valueArgumentList, jetClass));
} }
} }
@@ -205,7 +178,6 @@ public class BodyResolver {
if (classDescriptor != null) { if (classDescriptor != null) {
if (descriptor.getKind() != ClassKind.TRAIT) { if (descriptor.getKind() != ClassKind.TRAIT) {
if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && classDescriptor.getKind() != ClassKind.TRAIT) { if (classDescriptor.hasConstructors() && !ErrorUtils.isError(classDescriptor.getTypeConstructor()) && classDescriptor.getKind() != ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "This type has a constructor, and thus must be initialized here");
context.getTrace().report(SUPERTYPE_NOT_INITIALIZED.on(specifier)); context.getTrace().report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
} }
} }
@@ -249,7 +221,6 @@ public class BodyResolver {
if (classDescriptor != null) { if (classDescriptor != null) {
if (classDescriptor.getKind() != ClassKind.TRAIT) { if (classDescriptor.getKind() != ClassKind.TRAIT) {
if (classAppeared) { if (classAppeared) {
// context.getTrace().getErrorHandler().genericError(typeReference.getNode(), "Only one class may appear in a supertype list");
context.getTrace().report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference)); context.getTrace().report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference));
} }
else { else {
@@ -258,18 +229,15 @@ public class BodyResolver {
} }
} }
else { else {
// context.getTrace().getErrorHandler().genericError(typeReference.getNode(), "Only classes and traits may serve as supertypes");
context.getTrace().report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference)); context.getTrace().report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference));
} }
TypeConstructor constructor = supertype.getConstructor(); TypeConstructor constructor = supertype.getConstructor();
if (!typeConstructors.add(constructor)) { if (!typeConstructors.add(constructor)) {
// context.getTrace().getErrorHandler().genericError(typeReference.getNode(), "A supertype appears twice");
context.getTrace().report(SUPERTYPE_APPEARS_TWICE.on(typeReference)); context.getTrace().report(SUPERTYPE_APPEARS_TWICE.on(typeReference));
} }
if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) { if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) {
// context.getTrace().getErrorHandler().genericError(typeReference.getNode(), "This type is final, so it cannot be inherited from");
context.getTrace().report(FINAL_SUPERTYPE.on(typeReference)); context.getTrace().report(FINAL_SUPERTYPE.on(typeReference));
} }
} }
@@ -301,7 +269,6 @@ public class BodyResolver {
} }
else { else {
for (JetClassInitializer anonymousInitializer : anonymousInitializers) { for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
// context.getTrace().getErrorHandler().genericError(anonymousInitializer.getNode(), "Anonymous initializers are only allowed in the presence of a primary constructor");
context.getTrace().report(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR.on(anonymousInitializer)); context.getTrace().report(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR.on(anonymousInitializer));
} }
} }
@@ -326,13 +293,11 @@ public class BodyResolver {
JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class); JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class);
assert containingClass != null : "This must be guaranteed by the parser"; assert containingClass != null : "This must be guaranteed by the parser";
if (!containingClass.hasPrimaryConstructor()) { if (!containingClass.hasPrimaryConstructor()) {
// context.getTrace().getErrorHandler().genericError(declaration.getNameNode(), "A secondary constructor may appear only in a class that has a primary constructor");
context.getTrace().report(SECONDARY_CONSTRUCTOR_BUT_NO_PRIMARY.on(declaration.getNameNode())); context.getTrace().report(SECONDARY_CONSTRUCTOR_BUT_NO_PRIMARY.on(declaration.getNameNode()));
} }
else { else {
List<JetDelegationSpecifier> initializers = declaration.getInitializers(); List<JetDelegationSpecifier> initializers = declaration.getInitializers();
if (initializers.isEmpty()) { if (initializers.isEmpty()) {
// context.getTrace().getErrorHandler().genericError(declaration.getNameNode(), "Secondary constructors must have an initializer list");
context.getTrace().report(SECONDARY_CONSTRUCTOR_NO_INITIALIZER_LIST.on(declaration.getNameNode())); context.getTrace().report(SECONDARY_CONSTRUCTOR_NO_INITIALIZER_LIST.on(declaration.getNameNode()));
} }
else { else {
@@ -352,8 +317,8 @@ public class BodyResolver {
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(),
functionInnerScope, functionInnerScope,
ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
// call.getThisReference(), // call.getThisReference(),
// classDescriptor, // classDescriptor,
// classDescriptor.getDefaultType(), // classDescriptor.getDefaultType(),
@@ -363,13 +328,11 @@ public class BodyResolver {
@Override @Override
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "'by'-clause is only supported for primary constructors");
context.getTrace().report(BY_IN_SECONDARY_CONSTRUCTOR.on(specifier)); context.getTrace().report(BY_IN_SECONDARY_CONSTRUCTOR.on(specifier));
} }
@Override @Override
public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Constructor parameters required");
context.getTrace().report(INITIALIZER_WITH_NO_ARGUMENTS.on(specifier)); context.getTrace().report(INITIALIZER_WITH_NO_ARGUMENTS.on(specifier));
} }
@@ -380,7 +343,6 @@ public class BodyResolver {
}); });
for (int i = 1, initializersSize = initializers.size(); i < initializersSize; i++) { for (int i = 1, initializersSize = initializers.size(); i < initializersSize; i++) {
JetDelegationSpecifier initializer = initializers.get(i); JetDelegationSpecifier initializer = initializers.get(i);
// context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Only one call to 'this(...)' is allowed");
context.getTrace().report(MANY_CALLS_TO_THIS.on(initializer)); context.getTrace().report(MANY_CALLS_TO_THIS.on(initializer));
} }
} }
@@ -440,7 +402,6 @@ public class BodyResolver {
} }
resolvePropertyAccessors(property, propertyDescriptor, declaringScope); resolvePropertyAccessors(property, propertyDescriptor, declaringScope);
checkProperty(property, propertyDescriptor, classDescriptor);
processed.add(property); processed.add(property);
} }
} }
@@ -459,7 +420,6 @@ public class BodyResolver {
} }
resolvePropertyAccessors(property, propertyDescriptor, declaringScope); resolvePropertyAccessors(property, propertyDescriptor, declaringScope);
checkProperty(property, propertyDescriptor, null);
} }
} }
@@ -494,109 +454,6 @@ public class BodyResolver {
} }
} }
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
checkPropertyAbstractness(property, propertyDescriptor, classDescriptor);
checkPropertyInitializer(property, propertyDescriptor, classDescriptor);
}
private void checkPropertyAbstractness(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {
JetPropertyAccessor getter = property.getGetter();
JetPropertyAccessor setter = property.getSetter();
JetModifierList modifierList = property.getModifierList();
ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
if (abstractNode != null) { //has abstract modifier
if (classDescriptor == null) {
// context.getTrace().getErrorHandler().genericError(abstractNode, "A property may be abstract only when defined in a class or trait");
context.getTrace().report(ABSTRACT_PROPERTY_NOT_IN_CLASS.on(property, abstractNode));
return;
}
if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
// context.getTrace().getErrorHandler().genericError(abstractNode, "Abstract property " + property.getName() + " in non-abstract class " + classDescriptor.getName());
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, property.getName(), classDescriptor, (JetClass) classElement));
return;
}
if (classDescriptor.getKind() == ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericWarning(abstractNode, "Abstract modifier is redundant in traits");
context.getTrace().report(REDUNDANT_ABSTRACT.on(property, abstractNode));
}
}
if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
JetType returnType = propertyDescriptor.getReturnType();
if (returnType instanceof DeferredType) {
returnType = ((DeferredType) returnType).getActualType();
}
JetExpression initializer = property.getInitializer();
if (initializer != null) {
// context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property with initializer cannot be abstract");
context.getTrace().report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(property, initializer, returnType));
}
if (getter != null && getter.getBodyExpression() != null) {
// context.getTrace().getErrorHandler().genericError(getter.getNode(), "Property with getter implementation cannot be abstract");
context.getTrace().report(ABSTRACT_PROPERTY_WITH_GETTER.on(property, getter, returnType));
}
if (setter != null && setter.getBodyExpression() != null) {
// context.getTrace().getErrorHandler().genericError(setter.getNode(), "Property with setter implementation cannot be abstract");
context.getTrace().report(ABSTRACT_PROPERTY_WITH_SETTER.on(property, setter, returnType));
}
}
}
private void checkPropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {
JetPropertyAccessor getter = property.getGetter();
JetPropertyAccessor setter = property.getSetter();
boolean hasAccessorImplementation = (getter != null && getter.getBodyExpression() != null) ||
(setter != null && setter.getBodyExpression() != null);
if (propertyDescriptor.getModality() == Modality.ABSTRACT) return;
boolean inTrait = classDescriptor != null && classDescriptor.getKind() == ClassKind.TRAIT;
JetExpression initializer = property.getInitializer();
boolean backingFieldRequired = context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
PsiElement nameIdentifier = property.getNameIdentifier();
ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode();
if (inTrait && backingFieldRequired && hasAccessorImplementation) {
// context.getTrace().getErrorHandler().genericError(nameNode, "Property in a trait cannot have a backing field");
context.getTrace().report(BACKING_FIELD_IN_TRAIT.on(nameNode));
}
if (initializer == null) {
if (backingFieldRequired && !inTrait && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
if (classDescriptor == null || hasAccessorImplementation) {
// context.getTrace().getErrorHandler().genericError(nameNode, "Property must be initialized");
context.getTrace().report(MUST_BE_INITIALIZED.on(nameNode));
} else {
// context.getTrace().getErrorHandler().genericError(nameNode, "Property must be initialized or be abstract");
context.getTrace().report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property, nameNode));
}
}
return;
}
if (inTrait) {
// context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed in traits");
JetType returnType = propertyDescriptor.getReturnType();
if (returnType instanceof DeferredType) {
returnType = ((DeferredType) returnType).getActualType();
}
context.getTrace().report(PROPERTY_INITIALIZER_IN_TRAIT.on(property, initializer, returnType));
}
else if (!backingFieldRequired) {
// context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Initializer is not allowed here because this property has no backing field");
context.getTrace().report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
}
else if (classDescriptor != null && classDescriptor.getUnsubstitutedPrimaryConstructor() == null) {
// context.getTrace().getErrorHandler().genericError(initializer.getNode(), "Property initializers are not allowed when no primary constructor is present");
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR.on(property, initializer, (JetClass) classElement));
}
}
private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { private BindingTraceAdapter createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) {
return new BindingTraceAdapter(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() { return new BindingTraceAdapter(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
@Override @Override
@@ -647,13 +504,13 @@ public class BodyResolver {
private void resolveFunctionBodies() { private void resolveFunctionBodies() {
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) { for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) {
JetDeclaration declaration = entry.getKey(); JetNamedFunction declaration = entry.getKey();
FunctionDescriptor descriptor = entry.getValue(); FunctionDescriptor descriptor = entry.getValue();
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration); JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
assert declaringScope != null; assert declaringScope != null;
resolveFunctionBody(traceForMembers, (JetNamedFunction) declaration, descriptor, declaringScope); resolveFunctionBody(traceForMembers, declaration, descriptor, declaringScope);
assert descriptor.getReturnType() != null; assert descriptor.getReturnType() != null;
} }
@@ -673,60 +530,6 @@ public class BodyResolver {
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor); typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
} }
checkFunction(function, functionDescriptor);
assert functionDescriptor.getReturnType() != null; assert functionDescriptor.getReturnType() != null;
} }
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
PsiElement nameIdentifier;
boolean isPropertyAccessor = false;
if (function instanceof JetNamedFunction) {
nameIdentifier = ((JetNamedFunction) function).getNameIdentifier();
}
else if (function instanceof JetPropertyAccessor) {
isPropertyAccessor = true;
nameIdentifier = ((JetPropertyAccessor) function).getNamePlaceholder();
}
else {
throw new UnsupportedOperationException();
}
JetFunctionOrPropertyAccessor functionOrPropertyAccessor = (JetFunctionOrPropertyAccessor) function;
JetModifierList modifierList = functionOrPropertyAccessor.getModifierList();
ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
boolean hasAbstractModifier = abstractNode != null;
if (containingDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT;
boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS;
boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT;
if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) {
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(functionOrPropertyAccessor, abstractNode, functionDescriptor.getName(), classDescriptor, (JetClass) classElement));
}
if (hasAbstractModifier && inTrait && !isPropertyAccessor) {
context.getTrace().report(REDUNDANT_ABSTRACT.on(functionOrPropertyAccessor, abstractNode));
}
if (function.getBodyExpression() != null && hasAbstractModifier) {
context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(functionOrPropertyAccessor, abstractNode, functionDescriptor));
}
if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null && !isPropertyAccessor) {
context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor));
}
return;
}
if (hasAbstractModifier) {
if (!isPropertyAccessor) {
context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(functionOrPropertyAccessor, abstractNode, functionDescriptor));
}
else {
context.getTrace().report(NON_MEMBER_ABSTRACT_ACCESSOR.on(functionOrPropertyAccessor, abstractNode));
}
}
if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null && !isPropertyAccessor) {
context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor));
}
}
} }
@@ -21,8 +21,6 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetKeywordToken;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
@@ -67,8 +65,8 @@ public class ClassDescriptorResolver {
} }
descriptor.setTypeParameterDescriptors(typeParameters); descriptor.setTypeParameterDescriptors(typeParameters);
Modality defaultModality = descriptor.getKind() == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL; Modality defaultModality = descriptor.getKind() == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
descriptor.setModality(resolveModalityFromModifiers(trace, classElement.getModifierList(), defaultModality)); descriptor.setModality(resolveModalityFromModifiers(classElement.getModifierList(), defaultModality));
descriptor.setVisibility(resolveVisibilityFromModifiers(trace, classElement.getModifierList())); descriptor.setVisibility(resolveVisibilityFromModifiers(classElement.getModifierList()));
trace.record(BindingContext.CLASS, classElement, descriptor); trace.record(BindingContext.CLASS, classElement, descriptor);
} }
@@ -193,8 +191,8 @@ public class ClassDescriptorResolver {
} }
boolean hasBody = function.getBodyExpression() != null; boolean hasBody = function.getBodyExpression() != null;
Modality defaultModality = getDefaultModality(containingDescriptor, hasBody); Modality defaultModality = getDefaultModality(containingDescriptor, hasBody);
Modality modality = resolveModalityFromModifiers(trace, function.getModifierList(), defaultModality); Modality modality = resolveModalityFromModifiers(function.getModifierList(), defaultModality);
Visibility visibility = resolveVisibilityFromModifiers(trace, function.getModifierList()); Visibility visibility = resolveVisibilityFromModifiers(function.getModifierList());
functionDescriptor.initialize( functionDescriptor.initialize(
receiverType, receiverType,
typeParameterDescriptors, typeParameterDescriptors,
@@ -438,7 +436,7 @@ public class ClassDescriptorResolver {
containingDeclaration, containingDeclaration,
annotationResolver.createAnnotationStubs(modifierList), annotationResolver.createAnnotationStubs(modifierList),
Modality.FINAL, Modality.FINAL,
resolveVisibilityFromModifiers(trace, objectDeclaration.getModifierList()), resolveVisibilityFromModifiers(objectDeclaration.getModifierList()),
false, false,
null, null,
JetPsiUtil.safeName(objectDeclaration.getName()), JetPsiUtil.safeName(objectDeclaration.getName()),
@@ -499,8 +497,8 @@ public class ClassDescriptorResolver {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor( PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
containingDeclaration, containingDeclaration,
annotationResolver.resolveAnnotations(scope, modifierList), annotationResolver.resolveAnnotations(scope, modifierList),
resolveModalityFromModifiers(trace, property.getModifierList(), defaultModality), resolveModalityFromModifiers(property.getModifierList(), defaultModality),
resolveVisibilityFromModifiers(trace, property.getModifierList()), resolveVisibilityFromModifiers(property.getModifierList()),
isVar, isVar,
receiverType, receiverType,
JetPsiUtil.safeName(property.getName()), JetPsiUtil.safeName(property.getName()),
@@ -552,17 +550,12 @@ public class ClassDescriptorResolver {
} }
@NotNull @NotNull
/*package*/ static Modality resolveModalityFromModifiers(@NotNull BindingTrace trace, @Nullable JetModifierList modifierList, @NotNull Modality defaultModality) { /*package*/ static Modality resolveModalityFromModifiers(@Nullable JetModifierList modifierList, @NotNull Modality defaultModality) {
if (modifierList == null) return defaultModality; if (modifierList == null) return defaultModality;
checkCompatibility(trace, modifierList, Lists.newArrayList(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD),
Lists.<JetToken>newArrayList(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD));
boolean hasAbstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD); boolean hasAbstractModifier = modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD);
boolean hasOverrideModifier = modifierList.hasModifier(JetTokens.OVERRIDE_KEYWORD); boolean hasOverrideModifier = modifierList.hasModifier(JetTokens.OVERRIDE_KEYWORD);
if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) { if (modifierList.hasModifier(JetTokens.OPEN_KEYWORD)) {
if (hasAbstractModifier || hasOverrideModifier) {
trace.report(Errors.REDUNDANT_MODIFIER.on(modifierList, JetTokens.OPEN_KEYWORD, hasAbstractModifier ? JetTokens.ABSTRACT_KEYWORD : JetTokens.OVERRIDE_KEYWORD));
}
if (hasAbstractModifier || defaultModality == Modality.ABSTRACT) { if (hasAbstractModifier || defaultModality == Modality.ABSTRACT) {
return Modality.ABSTRACT; return Modality.ABSTRACT;
} }
@@ -582,15 +575,13 @@ public class ClassDescriptorResolver {
} }
@NotNull @NotNull
/*package*/ static Visibility resolveVisibilityFromModifiers(@NotNull BindingTrace trace, @Nullable JetModifierList modifierList) { /*package*/ static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList) {
return resolveVisibilityFromModifiers(trace, modifierList, Visibility.INTERNAL); return resolveVisibilityFromModifiers(modifierList, Visibility.INTERNAL);
} }
@NotNull @NotNull
/*package*/ static Visibility resolveVisibilityFromModifiers(@NotNull BindingTrace trace, @Nullable JetModifierList modifierList, @NotNull Visibility defaultVisibility) { /*package*/ static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList, @NotNull Visibility defaultVisibility) {
if (modifierList == null) return defaultVisibility; if (modifierList == null) return defaultVisibility;
checkCompatibility(trace, modifierList, Lists.newArrayList(JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PUBLIC_KEYWORD, JetTokens.INTERNAL_KEYWORD),
Lists.<JetToken>newArrayList(JetTokens.PROTECTED_KEYWORD, JetTokens.INTERNAL_KEYWORD));
if (modifierList.hasModifier(JetTokens.PRIVATE_KEYWORD)) return Visibility.PRIVATE; if (modifierList.hasModifier(JetTokens.PRIVATE_KEYWORD)) return Visibility.PRIVATE;
if (modifierList.hasModifier(JetTokens.PUBLIC_KEYWORD)) return Visibility.PUBLIC; if (modifierList.hasModifier(JetTokens.PUBLIC_KEYWORD)) return Visibility.PUBLIC;
if (modifierList.hasModifier(JetTokens.PROTECTED_KEYWORD)) { if (modifierList.hasModifier(JetTokens.PROTECTED_KEYWORD)) {
@@ -601,29 +592,7 @@ public class ClassDescriptorResolver {
} }
return defaultVisibility; return defaultVisibility;
} }
/*package*/ static boolean checkCompatibility(@NotNull BindingTrace trace, @Nullable JetModifierList modifierList, Collection<JetKeywordToken> availableModifiers, Collection<JetToken>... availableCombinations) {
if (modifierList == null) return true;
Collection<JetKeywordToken> presentModifiers = Sets.newLinkedHashSet();
for (JetKeywordToken modifier : availableModifiers) {
if (modifierList.hasModifier(modifier)) {
presentModifiers.add(modifier);
}
}
if (presentModifiers.size() == 1) {
return true;
}
for (Collection<JetToken> combination : availableCombinations) {
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
return true;
}
}
for (JetKeywordToken token : presentModifiers) {
trace.report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token), presentModifiers));
}
return false;
}
@Nullable @Nullable
private PropertySetterDescriptor resolvePropertySetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { private PropertySetterDescriptor resolvePropertySetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
JetPropertyAccessor setter = property.getSetter(); JetPropertyAccessor setter = property.getSetter();
@@ -633,8 +602,8 @@ public class ClassDescriptorResolver {
JetParameter parameter = setter.getParameter(); JetParameter parameter = setter.getParameter();
setterDescriptor = new PropertySetterDescriptor( setterDescriptor = new PropertySetterDescriptor(
resolveModalityFromModifiers(trace, setter.getModifierList(), propertyDescriptor.getModality()), resolveModalityFromModifiers(setter.getModifierList(), propertyDescriptor.getModality()),
resolveVisibilityFromModifiers(trace, setter.getModifierList(), propertyDescriptor.getVisibility()), resolveVisibilityFromModifiers(setter.getModifierList(), propertyDescriptor.getVisibility()),
propertyDescriptor, annotations, setter.getBodyExpression() != null, false); propertyDescriptor, annotations, setter.getBodyExpression() != null, false);
if (parameter != null) { if (parameter != null) {
if (parameter.isRef()) { if (parameter.isRef()) {
@@ -708,8 +677,8 @@ public class ClassDescriptorResolver {
} }
getterDescriptor = new PropertyGetterDescriptor( getterDescriptor = new PropertyGetterDescriptor(
propertyDescriptor, annotations, resolveModalityFromModifiers(trace, getter.getModifierList(), propertyDescriptor.getModality()), propertyDescriptor, annotations, resolveModalityFromModifiers(getter.getModifierList(), propertyDescriptor.getModality()),
resolveVisibilityFromModifiers(trace, getter.getModifierList(), propertyDescriptor.getVisibility()), resolveVisibilityFromModifiers(getter.getModifierList(), propertyDescriptor.getVisibility()),
returnType, getter.getBodyExpression() != null, false); returnType, getter.getBodyExpression() != null, false);
trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor); trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
} }
@@ -748,7 +717,7 @@ public class ClassDescriptorResolver {
new WritableScopeImpl(scope, classDescriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with value parameters of a constructor"), new WritableScopeImpl(scope, classDescriptor, new TraceBasedRedeclarationHandler(trace)).setDebugName("Scope with value parameters of a constructor"),
valueParameters), valueParameters),
Modality.FINAL, Modality.FINAL,
resolveVisibilityFromModifiers(trace, modifierList)); resolveVisibilityFromModifiers(modifierList));
} }
@Nullable @Nullable
@@ -784,8 +753,8 @@ public class ClassDescriptorResolver {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor( PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
classDescriptor, classDescriptor,
annotationResolver.resolveAnnotations(scope, modifierList), annotationResolver.resolveAnnotations(scope, modifierList),
resolveModalityFromModifiers(trace, parameter.getModifierList(), Modality.FINAL), resolveModalityFromModifiers(parameter.getModifierList(), Modality.FINAL),
resolveVisibilityFromModifiers(trace, parameter.getModifierList()), resolveVisibilityFromModifiers(parameter.getModifierList()),
isMutable, isMutable,
null, null,
name == null ? "<no name>" : name, name == null ? "<no name>" : name,
@@ -0,0 +1,352 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
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.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.DeferredType;
import org.jetbrains.jet.lang.types.JetType;
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.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
/**
* @author svtk
*/
public class DeclarationsChecker {
private TopDownAnalysisContext context;
public DeclarationsChecker(TopDownAnalysisContext context) {
this.context = context;
}
public void process() {
checkIfPrimaryConstructorIsNecessary();
Map<JetClass, MutableClassDescriptor> classes = context.getClasses();
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass aClass = entry.getKey();
MutableClassDescriptor classDescriptor = entry.getValue();
checkClass(aClass, classDescriptor);
checkModifiers(aClass.getModifierList());
}
Map<JetObjectDeclaration, MutableClassDescriptor> objects = context.getObjects();
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) {
JetObjectDeclaration objectDeclaration = entry.getKey();
MutableClassDescriptor objectDescriptor = entry.getValue();
checkObject(objectDeclaration, objectDescriptor);
}
Map<JetNamedFunction, FunctionDescriptorImpl> functions = context.getFunctions();
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : functions.entrySet()) {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
checkFunction(function, functionDescriptor);
checkModifiers(function.getModifierList());
}
Map<JetProperty, PropertyDescriptor> properties = context.getProperties();
for (Map.Entry<JetProperty, PropertyDescriptor> entry : properties.entrySet()) {
JetProperty property = entry.getKey();
PropertyDescriptor propertyDescriptor = entry.getValue();
checkProperty(property, propertyDescriptor);
checkModifiers(property.getModifierList());
}
}
private void checkIfPrimaryConstructorIsNecessary() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
PsiElement nameIdentifier = jetClass.getNameIdentifier();
if (nameIdentifier != null) {
context.getTrace().report(PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY.on(jetClass, nameIdentifier, propertyDescriptor));
}
break;
}
}
}
}
}
private void checkClass(JetClass aClass, MutableClassDescriptor classDescriptor) {
checkOpenMembers(aClass, classDescriptor);
checkTraitModifiers(aClass);
}
private void checkTraitModifiers(JetClass aClass) {
if (!aClass.isTrait()) return;
JetModifierList modifierList = aClass.getModifierList();
if (modifierList == null) return;
if (modifierList.hasModifier(JetTokens.FINAL_KEYWORD)) {
context.getTrace().report(Errors.TRAIT_CAN_NOT_BE_FINAL.on(aClass, modifierList.getModifierNode(JetTokens.FINAL_KEYWORD)));
}
ArrayList<JetKeywordToken> redundantModifiers = Lists.newArrayList(JetTokens.OPEN_KEYWORD, JetTokens.ABSTRACT_KEYWORD);
for (JetKeywordToken modifier : redundantModifiers) {
if (modifierList.hasModifier(modifier)) {
context.getTrace().report(Errors.REDUNDANT_MODIFIER_IN_TRAIT.on(modifierList, modifierList.getModifierNode(modifier), modifier));
}
}
}
private void checkObject(JetObjectDeclaration objectDeclaration, MutableClassDescriptor classDescriptor) {
checkIllegalInThisContextModifiers(objectDeclaration.getModifierList(), 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)) {
ASTNode openModifierNode = member.getModifierList().getModifierNode(JetTokens.OPEN_KEYWORD);
context.getTrace().report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member, openModifierNode, aClass));
}
}
}
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
ClassDescriptor classDescriptor = (containingDeclaration instanceof ClassDescriptor)
? (ClassDescriptor) containingDeclaration
: null;
checkPropertyAbstractness(property, propertyDescriptor, classDescriptor);
checkPropertyInitializer(property, propertyDescriptor, classDescriptor);
checkAccessors(property, propertyDescriptor);
}
private void checkPropertyAbstractness(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {
JetPropertyAccessor getter = property.getGetter();
JetPropertyAccessor setter = property.getSetter();
JetModifierList modifierList = property.getModifierList();
ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
if (abstractNode != null) { //has abstract modifier
if (classDescriptor == null) {
context.getTrace().report(ABSTRACT_PROPERTY_NOT_IN_CLASS.on(property, abstractNode));
return;
}
if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, property.getName(), classDescriptor, (JetClass) classElement));
return;
}
if (classDescriptor.getKind() == ClassKind.TRAIT) {
context.getTrace().report(REDUNDANT_ABSTRACT.on(property, abstractNode));
}
}
if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
JetType returnType = propertyDescriptor.getReturnType();
if (returnType instanceof DeferredType) {
returnType = ((DeferredType) returnType).getActualType();
}
JetExpression initializer = property.getInitializer();
if (initializer != null) {
context.getTrace().report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(property, initializer, returnType));
}
if (getter != null && getter.getBodyExpression() != null) {
context.getTrace().report(ABSTRACT_PROPERTY_WITH_GETTER.on(property, getter, returnType));
}
if (setter != null && setter.getBodyExpression() != null) {
context.getTrace().report(ABSTRACT_PROPERTY_WITH_SETTER.on(property, setter, returnType));
}
}
}
private void checkPropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, ClassDescriptor classDescriptor) {
JetPropertyAccessor getter = property.getGetter();
JetPropertyAccessor setter = property.getSetter();
boolean hasAccessorImplementation = (getter != null && getter.getBodyExpression() != null) ||
(setter != null && setter.getBodyExpression() != null);
if (propertyDescriptor.getModality() == Modality.ABSTRACT) return;
boolean inTrait = classDescriptor != null && classDescriptor.getKind() == ClassKind.TRAIT;
JetExpression initializer = property.getInitializer();
boolean backingFieldRequired = context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
PsiElement nameIdentifier = property.getNameIdentifier();
ASTNode nameNode = nameIdentifier == null ? property.getNode() : nameIdentifier.getNode();
if (inTrait && backingFieldRequired && hasAccessorImplementation) {
context.getTrace().report(BACKING_FIELD_IN_TRAIT.on(nameNode));
}
if (initializer == null) {
if (backingFieldRequired && !inTrait && !context.getTrace().getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
if (classDescriptor == null || hasAccessorImplementation) {
context.getTrace().report(MUST_BE_INITIALIZED.on(nameNode));
}
else {
context.getTrace().report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property, nameNode));
}
}
return;
}
if (inTrait) {
JetType returnType = propertyDescriptor.getReturnType();
if (returnType instanceof DeferredType) {
returnType = ((DeferredType) returnType).getActualType();
}
context.getTrace().report(PROPERTY_INITIALIZER_IN_TRAIT.on(property, initializer, returnType));
}
else if (!backingFieldRequired) {
context.getTrace().report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
}
else if (classDescriptor != null && classDescriptor.getUnsubstitutedPrimaryConstructor() == null) {
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR.on(property, initializer, (JetClass) classElement));
}
}
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
PsiElement nameIdentifier;
boolean isPropertyAccessor = false;
if (function instanceof JetNamedFunction) {
nameIdentifier = ((JetNamedFunction) function).getNameIdentifier();
}
else if (function instanceof JetPropertyAccessor) {
isPropertyAccessor = true;
nameIdentifier = ((JetPropertyAccessor) function).getNamePlaceholder();
}
else {
throw new UnsupportedOperationException();
}
JetFunctionOrPropertyAccessor functionOrPropertyAccessor = (JetFunctionOrPropertyAccessor) function;
JetModifierList modifierList = functionOrPropertyAccessor.getModifierList();
ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null;
boolean hasAbstractModifier = abstractNode != null;
if (containingDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDescriptor;
boolean inTrait = classDescriptor.getKind() == ClassKind.TRAIT;
boolean inEnum = classDescriptor.getKind() == ClassKind.ENUM_CLASS;
boolean inAbstractClass = classDescriptor.getModality() == Modality.ABSTRACT;
if (hasAbstractModifier && !inAbstractClass && !inTrait && !inEnum) {
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
assert classElement instanceof JetClass;
context.getTrace().report(ABSTRACT_FUNCTION_IN_NON_ABSTRACT_CLASS.on(functionOrPropertyAccessor, abstractNode, functionDescriptor.getName(), classDescriptor, (JetClass) classElement));
}
if (hasAbstractModifier && inTrait && !isPropertyAccessor) {
context.getTrace().report(REDUNDANT_ABSTRACT.on(functionOrPropertyAccessor, abstractNode));
}
if (function.getBodyExpression() != null && hasAbstractModifier) {
context.getTrace().report(ABSTRACT_FUNCTION_WITH_BODY.on(functionOrPropertyAccessor, abstractNode, functionDescriptor));
}
if (function.getBodyExpression() == null && !hasAbstractModifier && !inTrait && nameIdentifier != null && !isPropertyAccessor) {
context.getTrace().report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor));
}
return;
}
if (hasAbstractModifier) {
if (!isPropertyAccessor) {
context.getTrace().report(NON_MEMBER_ABSTRACT_FUNCTION.on(functionOrPropertyAccessor, abstractNode, functionDescriptor));
}
else {
context.getTrace().report(NON_MEMBER_ABSTRACT_ACCESSOR.on(functionOrPropertyAccessor, abstractNode));
}
}
if (function.getBodyExpression() == null && !hasAbstractModifier && nameIdentifier != null && !isPropertyAccessor) {
context.getTrace().report(NON_MEMBER_FUNCTION_NO_BODY.on(functionOrPropertyAccessor, nameIdentifier, functionDescriptor));
}
}
private void checkAccessors(JetProperty property, PropertyDescriptor propertyDescriptor) {
for (JetPropertyAccessor accessor : property.getAccessors()) {
PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter()
? propertyDescriptor.getGetter()
: propertyDescriptor.getSetter();
checkFunction(accessor, accessorDescriptor);
if (propertyDescriptor.getModality() == Modality.FINAL && accessor.hasModifier(JetTokens.OPEN_KEYWORD)) {
ASTNode openModifierNode = accessor.getModifierList().getModifierNode(JetTokens.OPEN_KEYWORD);
context.getTrace().report(NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY.on(accessor, openModifierNode, property));
}
}
}
private void checkModifiers(@Nullable JetModifierList modifierList) {
checkModalityModifiers(modifierList);
checkVisibilityModifiers(modifierList);
}
private void checkModalityModifiers(@Nullable JetModifierList modifierList) {
if (modifierList == null) return;
checkRedundantModifier(modifierList, Pair.create(JetTokens.OPEN_KEYWORD, JetTokens.ABSTRACT_KEYWORD), Pair.create(JetTokens.OPEN_KEYWORD, JetTokens.OVERRIDE_KEYWORD));
checkCompatibility(modifierList, Lists.newArrayList(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD),
Lists.<JetToken>newArrayList(JetTokens.ABSTRACT_KEYWORD, JetTokens.OPEN_KEYWORD));
}
private void checkVisibilityModifiers(@Nullable JetModifierList modifierList) {
if (modifierList == null) return;
checkCompatibility(modifierList, Lists.newArrayList(JetTokens.PRIVATE_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PUBLIC_KEYWORD, JetTokens.INTERNAL_KEYWORD),
Lists.<JetToken>newArrayList(JetTokens.PROTECTED_KEYWORD, JetTokens.INTERNAL_KEYWORD));
}
private void checkCompatibility(@Nullable JetModifierList modifierList, Collection<JetKeywordToken> availableModifiers, Collection<JetToken>... availableCombinations) {
if (modifierList == null) return;
Collection<JetKeywordToken> presentModifiers = Sets.newLinkedHashSet();
for (JetKeywordToken modifier : availableModifiers) {
if (modifierList.hasModifier(modifier)) {
presentModifiers.add(modifier);
}
}
if (presentModifiers.size() == 1) {
return;
}
for (Collection<JetToken> combination : availableCombinations) {
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
return;
}
}
for (JetKeywordToken token : presentModifiers) {
context.getTrace().report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token), presentModifiers));
}
}
private void checkRedundantModifier(@NotNull JetModifierList modifierList, Pair<JetKeywordToken, JetKeywordToken>... redundantBundles) {
for (Pair<JetKeywordToken, JetKeywordToken> tokenPair : redundantBundles) {
JetKeywordToken redundantModifier = tokenPair.getFirst();
JetKeywordToken sufficientModifier = tokenPair.getSecond();
if (modifierList.hasModifier(redundantModifier) && modifierList.hasModifier(sufficientModifier)) {
context.getTrace().report(Errors.REDUNDANT_MODIFIER.on(modifierList, modifierList.getModifierNode(redundantModifier), redundantModifier, sufficientModifier));
}
}
}
private void checkIllegalInThisContextModifiers(@Nullable JetModifierList modifierList, JetKeywordToken... illegalModifiers) {
if (modifierList == null) return;
for (JetKeywordToken modifier : illegalModifiers) {
if (modifierList.hasModifier(modifier)) {
context.getTrace().report(Errors.ILLEGAL_MODIFIER.on(modifierList.getModifierNode(modifier), modifier));
}
}
}
}
@@ -68,6 +68,7 @@ public class TopDownAnalyzer {
new DelegationResolver(context).process(); new DelegationResolver(context).process();
new OverrideResolver(context).process(); new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies(); new BodyResolver(context).resolveBehaviorDeclarationBodies();
new DeclarationsChecker(context).process();
} }
public static void processStandardLibraryNamespace( public static void processStandardLibraryNamespace(
@@ -86,16 +87,7 @@ public class TopDownAnalyzer {
} }
}; };
overrideResolver.process(); overrideResolver.process();
BodyResolver bodyResolver = new BodyResolver(context) { new BodyResolver(context).resolveBehaviorDeclarationBodies();
@Override
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
}
@Override
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
}
};
bodyResolver.resolveBehaviorDeclarationBodies();
} }
} }
@@ -98,7 +98,7 @@ public class TypeHierarchyResolver {
MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(context.getTrace(), mutableClassDescriptor, outerScope, ClassKind.OBJECT); MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(context.getTrace(), mutableClassDescriptor, outerScope, ClassKind.OBJECT);
classObjectDescriptor.setName("class-object-for-" + klass.getName()); classObjectDescriptor.setName("class-object-for-" + klass.getName());
classObjectDescriptor.setModality(Modality.FINAL); classObjectDescriptor.setModality(Modality.FINAL);
classObjectDescriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(context.getTrace(), klass.getModifierList())); classObjectDescriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(klass.getModifierList()));
classObjectDescriptor.createTypeConstructor(); classObjectDescriptor.createTypeConstructor();
createPrimaryConstructorForObject(null, classObjectDescriptor); createPrimaryConstructorForObject(null, classObjectDescriptor);
mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor); mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor);
@@ -274,7 +274,7 @@ public class TypeHierarchyResolver {
JetObjectDeclaration objectDeclaration = entry.getKey(); JetObjectDeclaration objectDeclaration = entry.getKey();
MutableClassDescriptor descriptor = entry.getValue(); MutableClassDescriptor descriptor = entry.getValue();
descriptor.setModality(Modality.FINAL); descriptor.setModality(Modality.FINAL);
descriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(context.getTrace(), objectDeclaration.getModifierList())); descriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(objectDeclaration.getModifierList()));
descriptor.createTypeConstructor(); descriptor.createTypeConstructor();
} }
} }
@@ -19,27 +19,16 @@ import org.jetbrains.jet.lexer.JetTokens;
*/ */
public class AddModifierFix extends ModifierFix { public class AddModifierFix extends ModifierFix {
private final JetToken[] modifiersThanCanBeReplaced; private final JetToken[] modifiersThanCanBeReplaced;
private final JetToken[] conflictedModifiers;
private AddModifierFix(@NotNull JetModifierListOwner element, JetKeywordToken modifier, JetToken[] modifiersThanCanBeReplaced, JetToken[] conflictedModifiers) { private AddModifierFix(@NotNull JetModifierListOwner element, JetKeywordToken modifier, JetToken[] modifiersThanCanBeReplaced) {
super(element, modifier); super(element, modifier);
this.modifiersThanCanBeReplaced = modifiersThanCanBeReplaced; this.modifiersThanCanBeReplaced = modifiersThanCanBeReplaced;
this.conflictedModifiers = conflictedModifiers;
}
private static boolean checkConflictModifiers(JetModifierListOwner element, JetToken[] conflictedModifiers) {
for (JetToken conflictedModifier : conflictedModifiers) {
if (element.hasModifier(conflictedModifier)) {
return true;
}
}
return false;
} }
@NotNull @NotNull
@Override @Override
public String getText() { public String getText() {
if (modifier == JetTokens.ABSTRACT_KEYWORD) { if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) {
return "Make " + getElementName() + " " + modifier.getValue(); return "Make " + getElementName() + " " + modifier.getValue();
} }
return "Add '" + modifier.getValue() + "' modifier"; return "Add '" + modifier.getValue() + "' modifier";
@@ -53,7 +42,7 @@ public class AddModifierFix extends ModifierFix {
@Override @Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return element.isValid() && !checkConflictModifiers(element, conflictedModifiers); return element.isValid();
} }
@Override @Override
@@ -97,17 +86,17 @@ public class AddModifierFix extends ModifierFix {
return true; return true;
} }
public static JetIntentionActionFactory<JetModifierListOwner> createFactory(final JetKeywordToken modifier, final JetToken[] modifiersThatCanBeReplaced, final JetToken[] conflictedModifiers) { public static JetIntentionActionFactory<JetModifierListOwner> createFactory(final JetKeywordToken modifier, final JetToken[] modifiersThatCanBeReplaced) {
return new JetIntentionActionFactory<JetModifierListOwner>() { return new JetIntentionActionFactory<JetModifierListOwner>() {
@Override @Override
public JetIntentionAction<JetModifierListOwner> createAction(DiagnosticWithPsiElement diagnostic) { public JetIntentionAction<JetModifierListOwner> createAction(DiagnosticWithPsiElement diagnostic) {
assert diagnostic.getPsiElement() instanceof JetModifierListOwner; assert diagnostic.getPsiElement() instanceof JetModifierListOwner;
return new AddModifierFix((JetModifierListOwner) diagnostic.getPsiElement(), modifier, modifiersThatCanBeReplaced, conflictedModifiers); return new AddModifierFix((JetModifierListOwner) diagnostic.getPsiElement(), modifier, modifiersThatCanBeReplaced);
} }
}; };
} }
public static JetIntentionActionFactory<JetModifierListOwner> createFactory(final JetKeywordToken modifier) { public static JetIntentionActionFactory<JetModifierListOwner> createFactory(final JetKeywordToken modifier) {
return createFactory(modifier, new JetToken[0], new JetToken[0]); return createFactory(modifier, new JetToken[0]);
} }
} }
@@ -30,7 +30,7 @@ public class QuickFixes {
static { static {
JetIntentionActionFactory<JetModifierListOwner> removeAbstractModifierFactory = RemoveModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD); JetIntentionActionFactory<JetModifierListOwner> removeAbstractModifierFactory = RemoveModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD);
JetIntentionActionFactory<JetModifierListOwner> addAbstractModifierFactory = AddModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD, new JetToken[]{JetTokens.OPEN_KEYWORD}, new JetToken[] {JetTokens.FINAL_KEYWORD}); JetIntentionActionFactory<JetModifierListOwner> addAbstractModifierFactory = AddModifierFix.createFactory(JetTokens.ABSTRACT_KEYWORD, new JetToken[]{JetTokens.OPEN_KEYWORD, JetTokens.FINAL_KEYWORD});
add(Errors.ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, removeAbstractModifierFactory); add(Errors.ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, removeAbstractModifierFactory);
add(Errors.ABSTRACT_PROPERTY_NOT_IN_CLASS, removeAbstractModifierFactory); add(Errors.ABSTRACT_PROPERTY_NOT_IN_CLASS, removeAbstractModifierFactory);
@@ -84,14 +84,24 @@ public class QuickFixes {
add(Errors.USELESS_ELVIS, RemoveRightPartOfBinaryExpressionFix.createRemoveElvisOperatorFactory()); add(Errors.USELESS_ELVIS, RemoveRightPartOfBinaryExpressionFix.createRemoveElvisOperatorFactory());
add(Errors.UNNECESSARY_SAFE_CALL, ReplaceSafeCallToDotCall.createFactory()); add(Errors.UNNECESSARY_SAFE_CALL, ReplaceSafeCallToDotCall.createFactory());
add(Errors.REDUNDANT_MODIFIER, RemoveRedundantModifierFix.createFactory()); JetIntentionActionFactory<JetModifierList> removeRedundantModifierFactory = RemoveRedundantModifierFix.createFactory();
add(Errors.REDUNDANT_MODIFIER, removeRedundantModifierFactory);
add(Errors.REDUNDANT_MODIFIER_IN_TRAIT, removeRedundantModifierFactory);
add(Errors.TRAIT_CAN_NOT_BE_FINAL, RemoveModifierFix.createFactory(JetTokens.FINAL_KEYWORD));
add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, RemovePartsFromPropertyFix.createRemoveInitializerFactory()); add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, RemovePartsFromPropertyFix.createRemoveInitializerFactory());
JetIntentionActionFactory<JetClass> addPrimaryConstructorFactory = AddPrimaryConstructorFix.createFactory(); JetIntentionActionFactory<JetClass> addPrimaryConstructorFactory = AddPrimaryConstructorFix.createFactory();
add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addPrimaryConstructorFactory, DiagnosticParameters.CLASS)); add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addPrimaryConstructorFactory, DiagnosticParameters.CLASS));
add(Errors.PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY, addPrimaryConstructorFactory); add(Errors.PRIMARY_CONSTRUCTOR_MISSING_STATEFUL_PROPERTY, addPrimaryConstructorFactory);
JetIntentionActionFactory<JetModifierListOwner> addOpenModifierFactory = AddModifierFix.createFactory(JetTokens.OPEN_KEYWORD, new JetToken[]{JetTokens.FINAL_KEYWORD});
JetIntentionActionFactory<JetModifierListOwner> removeOpenModifierFactory = RemoveModifierFix.createFactory(JetTokens.OPEN_KEYWORD);
add(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addOpenModifierFactory, DiagnosticParameters.CLASS));
add(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, removeOpenModifierFactory);
add(Errors.NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addOpenModifierFactory, DiagnosticParameters.PROPERTY));
add(Errors.NON_FINAL_ACCESSOR_OF_FINAL_PROPERTY, removeOpenModifierFactory);
} }
} }
@@ -29,7 +29,7 @@ public class RemoveModifierFix extends ModifierFix {
@NotNull @NotNull
@Override @Override
public String getText() { public String getText() {
if (modifier == JetTokens.ABSTRACT_KEYWORD) { if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) {
return "Make " + getElementName() + " not " + modifier.getValue(); return "Make " + getElementName() + " not " + modifier.getValue();
} }
return "Remove '" + modifier.getValue() + "' modifier"; return "Remove '" + modifier.getValue() + "' modifier";
+8 -8
View File
@@ -1,13 +1,13 @@
open trait A { trait A {
fun foo() {} fun foo() {}
} }
open trait B : A, <error>E</error> {} trait B : A, <error>E</error> {}
open trait C : B {} trait C : B {}
open trait D : <error>B</error> {} trait D : <error>B</error> {}
open trait E : <error>F</error> {} trait E : <error>F</error> {}
open trait F : <error>D</error>, C {} trait F : <error>D</error>, C {}
open trait G : F {} trait G : F {}
open trait H : F {} trait H : F {}
val a : A? = null val a : A? = null
val b : B? = null val b : B? = null
@@ -1,13 +1,13 @@
open trait A { trait A {
fun foo() {} fun foo() {}
} }
open trait B : A, <!CYCLIC_INHERITANCE_HIERARCHY!>E<!> {} trait B : A, <!CYCLIC_INHERITANCE_HIERARCHY!>E<!> {}
open trait C : B {} trait C : B {}
open trait D : <!CYCLIC_INHERITANCE_HIERARCHY!>B<!> {} trait D : <!CYCLIC_INHERITANCE_HIERARCHY!>B<!> {}
open trait E : <!CYCLIC_INHERITANCE_HIERARCHY!>F<!> {} trait E : <!CYCLIC_INHERITANCE_HIERARCHY!>F<!> {}
open trait F : <!CYCLIC_INHERITANCE_HIERARCHY!>D<!>, C {} trait F : <!CYCLIC_INHERITANCE_HIERARCHY!>D<!>, C {}
open trait G : F {} trait G : F {}
open trait H : F {} trait H : F {}
val a : A? = null val a : A? = null
val b : B? = null val b : B? = null
@@ -0,0 +1,7 @@
namespace a
abstract class A() {
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>final<!> fun f()
abstract <!REDUNDANT_MODIFIER!>open<!> fun g()
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>open<!> fun h() {}
}
@@ -1,4 +0,0 @@
// "Make 'foo' abstract" "false"
class B() {
final fun <caret>foo()
}
@@ -4,5 +4,5 @@ abstract class B() {
} }
abstract class A() : B() { abstract class A() : B() {
<caret>abstract override fun foo() abstract <caret>override fun foo()
} }
@@ -4,5 +4,5 @@ abstract class B() {
} }
abstract class A() : B() { abstract class A() : B() {
<caret>abstract override fun foo() abstract override<caret> fun foo()
} }
@@ -4,5 +4,5 @@ abstract class B() {
} }
abstract class A() : B() { abstract class A() : B() {
<caret>abstract open override fun foo() abstract <caret>open override fun foo()
} }
@@ -4,5 +4,5 @@ abstract class B() {
} }
abstract class A() : B() { abstract class A() : B() {
<caret>abstract override open fun foo() abstract override <caret>open fun foo()
} }