Modifiers checks were moved to DeclarationsChecker; added 'open' modifier checks
This commit is contained in:
+2
-2
@@ -27,8 +27,8 @@ public abstract class DiagnosticFactoryWithPsiElement1<T extends PsiElement, A>
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A argument) {
|
||||
return on(element, element.getTextRange(), argument);
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A argument) {
|
||||
return on(elementToMark, elementToMark.getTextRange(), argument);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@ public abstract class DiagnosticFactoryWithPsiElement2<T extends PsiElement, A,
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A a, @NotNull B b) {
|
||||
return on(element, element.getNode(), a, b);
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A a, @NotNull B b) {
|
||||
return on(elementToMark, elementToMark.getNode(), a, b);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ public abstract class DiagnosticFactoryWithPsiElement3<T extends PsiElement, A,
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T element, @NotNull A a, @NotNull B b, @NotNull C c) {
|
||||
return on(element, element, a, b, c);
|
||||
public DiagnosticWithPsiElement<T> on(@NotNull T elementToMark, @NotNull A a, @NotNull B b, @NotNull C c) {
|
||||
return on(elementToMark, elementToMark, a, b, c);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.diagnostics;
|
||||
|
||||
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.lexer.JetKeywordToken;
|
||||
|
||||
@@ -11,4 +12,5 @@ public interface DiagnosticParameters {
|
||||
DiagnosticParameter<JetKeywordToken> MODIFIER = new DiagnosticParameterImpl<JetKeywordToken>("MODIFIER");
|
||||
DiagnosticParameter<JetClass> CLASS = new DiagnosticParameterImpl<JetClass>("CLASS");
|
||||
DiagnosticParameter<JetType> TYPE = new DiagnosticParameterImpl<JetType>("TYPE");
|
||||
DiagnosticParameter<JetProperty> PROPERTY = new DiagnosticParameterImpl<JetProperty>("TYPE");
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public interface Errors {
|
||||
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") {
|
||||
@NotNull
|
||||
@@ -67,6 +68,8 @@ public interface Errors {
|
||||
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 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");
|
||||
@@ -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
|
||||
|
||||
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 SUPERTYPE_NOT_INITIALIZED = SimpleDiagnosticFactory.create(ERROR, "This type has a constructor, and thus must be initialized here");
|
||||
|
||||
+4
-4
@@ -27,12 +27,12 @@ public class ParameterizedDiagnosticFactory1<A> extends DiagnosticFactoryWithPsi
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A argument) {
|
||||
return new GenericDiagnostic(this, severity, makeMessage(argument), psiFile, range);
|
||||
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange rangeToMark, @NotNull A argument) {
|
||||
return new GenericDiagnostic(this, severity, makeMessage(argument), psiFile, rangeToMark);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull ASTNode node, @NotNull A argument) {
|
||||
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), argument);
|
||||
public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A argument) {
|
||||
return on(DiagnosticUtils.getContainingFile(nodeToMark), nodeToMark.getTextRange(), argument);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -27,13 +27,13 @@ public class ParameterizedDiagnosticFactory2<A, B> extends DiagnosticFactoryWith
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A a, @NotNull B b) {
|
||||
return new GenericDiagnostic(this, severity, makeMessage(a, b), psiFile, range);
|
||||
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange rangeToMark, @NotNull A a, @NotNull B b) {
|
||||
return new GenericDiagnostic(this, severity, makeMessage(a, b), psiFile, rangeToMark);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull ASTNode node, @NotNull A a, @NotNull B b) {
|
||||
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), a, b);
|
||||
public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A a, @NotNull B b) {
|
||||
return on(DiagnosticUtils.getContainingFile(nodeToMark), nodeToMark.getTextRange(), a, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -27,12 +27,12 @@ public class ParameterizedDiagnosticFactory3<A, B, C> extends DiagnosticFactoryW
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull PsiFile psiFile, @NotNull TextRange range, @NotNull A a, @NotNull B b, @NotNull C c) {
|
||||
return new GenericDiagnostic(this, severity, makeMessage(a, b, c), psiFile, range);
|
||||
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, rangeToMark);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull ASTNode node, @NotNull A a, @NotNull B b, @NotNull C c) {
|
||||
return on(DiagnosticUtils.getContainingFile(node), node.getTextRange(), a, b, c);
|
||||
public Diagnostic on(@NotNull ASTNode nodeToMark, @NotNull A a, @NotNull B b, @NotNull C 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.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
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.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.types.JetTypeInferrer.NO_EXPECTED_TYPE;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
* @author abreslav
|
||||
*/
|
||||
public class BodyResolver {
|
||||
private final TopDownAnalysisContext context;
|
||||
|
||||
@@ -43,7 +44,6 @@ public class BodyResolver {
|
||||
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression;
|
||||
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,6 @@ public class BodyResolver {
|
||||
|
||||
|
||||
public void resolveBehaviorDeclarationBodies() {
|
||||
// bindOverrides();
|
||||
|
||||
resolveDelegationSpecifierLists();
|
||||
resolveClassAnnotations();
|
||||
@@ -79,30 +78,9 @@ public class BodyResolver {
|
||||
resolveSecondaryConstructorBodies();
|
||||
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() {
|
||||
// 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) {
|
||||
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
|
||||
final JetScope scopeForConstructor = primaryConstructor == null
|
||||
? null
|
||||
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
|
||||
? null
|
||||
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
|
||||
final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
|
||||
|
||||
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
|
||||
@@ -131,7 +109,6 @@ public class BodyResolver {
|
||||
@Override
|
||||
public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) {
|
||||
if (descriptor.getKind() == ClassKind.TRAIT) {
|
||||
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Traits cannot use delegation");
|
||||
context.getTrace().report(DELEGATION_IN_TRAIT.on(specifier));
|
||||
}
|
||||
JetType supertype = context.getTrace().getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
|
||||
@@ -162,7 +139,6 @@ public class BodyResolver {
|
||||
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
|
||||
ASTNode node = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode();
|
||||
if (descriptor.getKind() == ClassKind.TRAIT) {
|
||||
// context.getTrace().getErrorHandler().genericError(node, "Traits cannot initialize supertypes");
|
||||
context.getTrace().report(SUPERTYPE_INITIALIZED_IN_TRAIT.on(node));
|
||||
}
|
||||
JetTypeReference typeReference = call.getTypeReference();
|
||||
@@ -174,7 +150,6 @@ public class BodyResolver {
|
||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
|
||||
if (classDescriptor != null) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -188,8 +163,6 @@ public class BodyResolver {
|
||||
recordSupertype(typeReference, supertype);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -205,7 +178,6 @@ public class BodyResolver {
|
||||
if (classDescriptor != null) {
|
||||
if (descriptor.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));
|
||||
}
|
||||
}
|
||||
@@ -249,7 +221,6 @@ public class BodyResolver {
|
||||
if (classDescriptor != null) {
|
||||
if (classDescriptor.getKind() != ClassKind.TRAIT) {
|
||||
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));
|
||||
}
|
||||
else {
|
||||
@@ -258,18 +229,15 @@ public class BodyResolver {
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
TypeConstructor constructor = supertype.getConstructor();
|
||||
if (!typeConstructors.add(constructor)) {
|
||||
// context.getTrace().getErrorHandler().genericError(typeReference.getNode(), "A supertype appears twice");
|
||||
context.getTrace().report(SUPERTYPE_APPEARS_TWICE.on(typeReference));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -301,7 +269,6 @@ public class BodyResolver {
|
||||
}
|
||||
else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -326,13 +293,11 @@ public class BodyResolver {
|
||||
JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class);
|
||||
assert containingClass != null : "This must be guaranteed by the parser";
|
||||
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()));
|
||||
}
|
||||
else {
|
||||
List<JetDelegationSpecifier> initializers = declaration.getInitializers();
|
||||
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()));
|
||||
}
|
||||
else {
|
||||
@@ -352,8 +317,8 @@ public class BodyResolver {
|
||||
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
|
||||
typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(),
|
||||
functionInnerScope,
|
||||
ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
|
||||
functionInnerScope,
|
||||
ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE);
|
||||
// call.getThisReference(),
|
||||
// classDescriptor,
|
||||
// classDescriptor.getDefaultType(),
|
||||
@@ -363,13 +328,11 @@ public class BodyResolver {
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) {
|
||||
// context.getTrace().getErrorHandler().genericError(specifier.getNode(), "Constructor parameters required");
|
||||
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++) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -440,7 +402,6 @@ public class BodyResolver {
|
||||
}
|
||||
|
||||
resolvePropertyAccessors(property, propertyDescriptor, declaringScope);
|
||||
checkProperty(property, propertyDescriptor, classDescriptor);
|
||||
processed.add(property);
|
||||
}
|
||||
}
|
||||
@@ -459,7 +420,6 @@ public class BodyResolver {
|
||||
}
|
||||
|
||||
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) {
|
||||
return new BindingTraceAdapter(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new BindingTraceAdapter.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
|
||||
@Override
|
||||
@@ -647,13 +504,13 @@ public class BodyResolver {
|
||||
|
||||
private void resolveFunctionBodies() {
|
||||
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : this.context.getFunctions().entrySet()) {
|
||||
JetDeclaration declaration = entry.getKey();
|
||||
JetNamedFunction declaration = entry.getKey();
|
||||
FunctionDescriptor descriptor = entry.getValue();
|
||||
|
||||
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
|
||||
assert declaringScope != null;
|
||||
|
||||
resolveFunctionBody(traceForMembers, (JetNamedFunction) declaration, descriptor, declaringScope);
|
||||
resolveFunctionBody(traceForMembers, declaration, descriptor, declaringScope);
|
||||
|
||||
assert descriptor.getReturnType() != null;
|
||||
}
|
||||
@@ -673,60 +530,6 @@ public class BodyResolver {
|
||||
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
|
||||
}
|
||||
|
||||
checkFunction(function, functionDescriptor);
|
||||
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.WritableScopeImpl;
|
||||
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 java.util.*;
|
||||
@@ -67,8 +65,8 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
descriptor.setTypeParameterDescriptors(typeParameters);
|
||||
Modality defaultModality = descriptor.getKind() == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
|
||||
descriptor.setModality(resolveModalityFromModifiers(trace, classElement.getModifierList(), defaultModality));
|
||||
descriptor.setVisibility(resolveVisibilityFromModifiers(trace, classElement.getModifierList()));
|
||||
descriptor.setModality(resolveModalityFromModifiers(classElement.getModifierList(), defaultModality));
|
||||
descriptor.setVisibility(resolveVisibilityFromModifiers(classElement.getModifierList()));
|
||||
|
||||
trace.record(BindingContext.CLASS, classElement, descriptor);
|
||||
}
|
||||
@@ -193,8 +191,8 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
boolean hasBody = function.getBodyExpression() != null;
|
||||
Modality defaultModality = getDefaultModality(containingDescriptor, hasBody);
|
||||
Modality modality = resolveModalityFromModifiers(trace, function.getModifierList(), defaultModality);
|
||||
Visibility visibility = resolveVisibilityFromModifiers(trace, function.getModifierList());
|
||||
Modality modality = resolveModalityFromModifiers(function.getModifierList(), defaultModality);
|
||||
Visibility visibility = resolveVisibilityFromModifiers(function.getModifierList());
|
||||
functionDescriptor.initialize(
|
||||
receiverType,
|
||||
typeParameterDescriptors,
|
||||
@@ -438,7 +436,7 @@ public class ClassDescriptorResolver {
|
||||
containingDeclaration,
|
||||
annotationResolver.createAnnotationStubs(modifierList),
|
||||
Modality.FINAL,
|
||||
resolveVisibilityFromModifiers(trace, objectDeclaration.getModifierList()),
|
||||
resolveVisibilityFromModifiers(objectDeclaration.getModifierList()),
|
||||
false,
|
||||
null,
|
||||
JetPsiUtil.safeName(objectDeclaration.getName()),
|
||||
@@ -499,8 +497,8 @@ public class ClassDescriptorResolver {
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
||||
containingDeclaration,
|
||||
annotationResolver.resolveAnnotations(scope, modifierList),
|
||||
resolveModalityFromModifiers(trace, property.getModifierList(), defaultModality),
|
||||
resolveVisibilityFromModifiers(trace, property.getModifierList()),
|
||||
resolveModalityFromModifiers(property.getModifierList(), defaultModality),
|
||||
resolveVisibilityFromModifiers(property.getModifierList()),
|
||||
isVar,
|
||||
receiverType,
|
||||
JetPsiUtil.safeName(property.getName()),
|
||||
@@ -552,17 +550,12 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
|
||||
@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;
|
||||
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 hasOverrideModifier = modifierList.hasModifier(JetTokens.OVERRIDE_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) {
|
||||
return Modality.ABSTRACT;
|
||||
}
|
||||
@@ -582,15 +575,13 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static Visibility resolveVisibilityFromModifiers(@NotNull BindingTrace trace, @Nullable JetModifierList modifierList) {
|
||||
return resolveVisibilityFromModifiers(trace, modifierList, Visibility.INTERNAL);
|
||||
/*package*/ static Visibility resolveVisibilityFromModifiers(@Nullable JetModifierList modifierList) {
|
||||
return resolveVisibilityFromModifiers(modifierList, Visibility.INTERNAL);
|
||||
}
|
||||
|
||||
@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;
|
||||
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.PUBLIC_KEYWORD)) return Visibility.PUBLIC;
|
||||
if (modifierList.hasModifier(JetTokens.PROTECTED_KEYWORD)) {
|
||||
@@ -601,29 +592,7 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
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
|
||||
private PropertySetterDescriptor resolvePropertySetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
JetPropertyAccessor setter = property.getSetter();
|
||||
@@ -633,8 +602,8 @@ public class ClassDescriptorResolver {
|
||||
JetParameter parameter = setter.getParameter();
|
||||
|
||||
setterDescriptor = new PropertySetterDescriptor(
|
||||
resolveModalityFromModifiers(trace, setter.getModifierList(), propertyDescriptor.getModality()),
|
||||
resolveVisibilityFromModifiers(trace, setter.getModifierList(), propertyDescriptor.getVisibility()),
|
||||
resolveModalityFromModifiers(setter.getModifierList(), propertyDescriptor.getModality()),
|
||||
resolveVisibilityFromModifiers(setter.getModifierList(), propertyDescriptor.getVisibility()),
|
||||
propertyDescriptor, annotations, setter.getBodyExpression() != null, false);
|
||||
if (parameter != null) {
|
||||
if (parameter.isRef()) {
|
||||
@@ -708,8 +677,8 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
|
||||
getterDescriptor = new PropertyGetterDescriptor(
|
||||
propertyDescriptor, annotations, resolveModalityFromModifiers(trace, getter.getModifierList(), propertyDescriptor.getModality()),
|
||||
resolveVisibilityFromModifiers(trace, getter.getModifierList(), propertyDescriptor.getVisibility()),
|
||||
propertyDescriptor, annotations, resolveModalityFromModifiers(getter.getModifierList(), propertyDescriptor.getModality()),
|
||||
resolveVisibilityFromModifiers(getter.getModifierList(), propertyDescriptor.getVisibility()),
|
||||
returnType, getter.getBodyExpression() != null, false);
|
||||
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"),
|
||||
valueParameters),
|
||||
Modality.FINAL,
|
||||
resolveVisibilityFromModifiers(trace, modifierList));
|
||||
resolveVisibilityFromModifiers(modifierList));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -784,8 +753,8 @@ public class ClassDescriptorResolver {
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
||||
classDescriptor,
|
||||
annotationResolver.resolveAnnotations(scope, modifierList),
|
||||
resolveModalityFromModifiers(trace, parameter.getModifierList(), Modality.FINAL),
|
||||
resolveVisibilityFromModifiers(trace, parameter.getModifierList()),
|
||||
resolveModalityFromModifiers(parameter.getModifierList(), Modality.FINAL),
|
||||
resolveVisibilityFromModifiers(parameter.getModifierList()),
|
||||
isMutable,
|
||||
null,
|
||||
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 OverrideResolver(context).process();
|
||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||
new DeclarationsChecker(context).process();
|
||||
}
|
||||
|
||||
public static void processStandardLibraryNamespace(
|
||||
@@ -86,16 +87,7 @@ public class TopDownAnalyzer {
|
||||
}
|
||||
};
|
||||
overrideResolver.process();
|
||||
BodyResolver bodyResolver = new BodyResolver(context) {
|
||||
@Override
|
||||
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
|
||||
}
|
||||
};
|
||||
bodyResolver.resolveBehaviorDeclarationBodies();
|
||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class TypeHierarchyResolver {
|
||||
MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(context.getTrace(), mutableClassDescriptor, outerScope, ClassKind.OBJECT);
|
||||
classObjectDescriptor.setName("class-object-for-" + klass.getName());
|
||||
classObjectDescriptor.setModality(Modality.FINAL);
|
||||
classObjectDescriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(context.getTrace(), klass.getModifierList()));
|
||||
classObjectDescriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(klass.getModifierList()));
|
||||
classObjectDescriptor.createTypeConstructor();
|
||||
createPrimaryConstructorForObject(null, classObjectDescriptor);
|
||||
mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor);
|
||||
@@ -274,7 +274,7 @@ public class TypeHierarchyResolver {
|
||||
JetObjectDeclaration objectDeclaration = entry.getKey();
|
||||
MutableClassDescriptor descriptor = entry.getValue();
|
||||
descriptor.setModality(Modality.FINAL);
|
||||
descriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(context.getTrace(), objectDeclaration.getModifierList()));
|
||||
descriptor.setVisibility(ClassDescriptorResolver.resolveVisibilityFromModifiers(objectDeclaration.getModifierList()));
|
||||
descriptor.createTypeConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,27 +19,16 @@ import org.jetbrains.jet.lexer.JetTokens;
|
||||
*/
|
||||
public class AddModifierFix extends ModifierFix {
|
||||
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);
|
||||
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
|
||||
@Override
|
||||
public String getText() {
|
||||
if (modifier == JetTokens.ABSTRACT_KEYWORD) {
|
||||
if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) {
|
||||
return "Make " + getElementName() + " " + modifier.getValue();
|
||||
}
|
||||
return "Add '" + modifier.getValue() + "' modifier";
|
||||
@@ -53,7 +42,7 @@ public class AddModifierFix extends ModifierFix {
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
return element.isValid() && !checkConflictModifiers(element, conflictedModifiers);
|
||||
return element.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,17 +86,17 @@ public class AddModifierFix extends ModifierFix {
|
||||
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>() {
|
||||
@Override
|
||||
public JetIntentionAction<JetModifierListOwner> createAction(DiagnosticWithPsiElement diagnostic) {
|
||||
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) {
|
||||
return createFactory(modifier, new JetToken[0], new JetToken[0]);
|
||||
return createFactory(modifier, new JetToken[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class QuickFixes {
|
||||
|
||||
static {
|
||||
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_NOT_IN_CLASS, removeAbstractModifierFactory);
|
||||
@@ -84,14 +84,24 @@ public class QuickFixes {
|
||||
add(Errors.USELESS_ELVIS, RemoveRightPartOfBinaryExpressionFix.createRemoveElvisOperatorFactory());
|
||||
|
||||
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());
|
||||
|
||||
JetIntentionActionFactory<JetClass> addPrimaryConstructorFactory = AddPrimaryConstructorFix.createFactory();
|
||||
add(Errors.PROPERTY_INITIALIZER_NO_PRIMARY_CONSTRUCTOR, QuickFixUtil.createFactoryRedirectingAdditionalInfoToAnotherFactory(addPrimaryConstructorFactory, DiagnosticParameters.CLASS));
|
||||
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
|
||||
@Override
|
||||
public String getText() {
|
||||
if (modifier == JetTokens.ABSTRACT_KEYWORD) {
|
||||
if (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) {
|
||||
return "Make " + getElementName() + " not " + modifier.getValue();
|
||||
}
|
||||
return "Remove '" + modifier.getValue() + "' modifier";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
open trait A {
|
||||
trait A {
|
||||
fun foo() {}
|
||||
}
|
||||
open trait B : A, <error>E</error> {}
|
||||
open trait C : B {}
|
||||
open trait D : <error>B</error> {}
|
||||
open trait E : <error>F</error> {}
|
||||
open trait F : <error>D</error>, C {}
|
||||
open trait G : F {}
|
||||
open trait H : F {}
|
||||
trait B : A, <error>E</error> {}
|
||||
trait C : B {}
|
||||
trait D : <error>B</error> {}
|
||||
trait E : <error>F</error> {}
|
||||
trait F : <error>D</error>, C {}
|
||||
trait G : F {}
|
||||
trait H : F {}
|
||||
|
||||
val a : A? = null
|
||||
val b : B? = null
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
open trait A {
|
||||
trait A {
|
||||
fun foo() {}
|
||||
}
|
||||
open trait B : A, <!CYCLIC_INHERITANCE_HIERARCHY!>E<!> {}
|
||||
open trait C : B {}
|
||||
open trait D : <!CYCLIC_INHERITANCE_HIERARCHY!>B<!> {}
|
||||
open trait E : <!CYCLIC_INHERITANCE_HIERARCHY!>F<!> {}
|
||||
open trait F : <!CYCLIC_INHERITANCE_HIERARCHY!>D<!>, C {}
|
||||
open trait G : F {}
|
||||
open trait H : F {}
|
||||
trait B : A, <!CYCLIC_INHERITANCE_HIERARCHY!>E<!> {}
|
||||
trait C : B {}
|
||||
trait D : <!CYCLIC_INHERITANCE_HIERARCHY!>B<!> {}
|
||||
trait E : <!CYCLIC_INHERITANCE_HIERARCHY!>F<!> {}
|
||||
trait F : <!CYCLIC_INHERITANCE_HIERARCHY!>D<!>, C {}
|
||||
trait G : F {}
|
||||
trait H : F {}
|
||||
|
||||
val a : A? = 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() {
|
||||
<caret>abstract override fun foo()
|
||||
abstract <caret>override fun foo()
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ abstract class 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() {
|
||||
<caret>abstract open override fun foo()
|
||||
abstract <caret>open override fun foo()
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ abstract class B() {
|
||||
}
|
||||
|
||||
abstract class A() : B() {
|
||||
<caret>abstract override open fun foo()
|
||||
abstract override <caret>open fun foo()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user