Added check for incompatible variance modifiers and repeated modifiers
This commit is contained in:
@@ -111,6 +111,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory1<PsiElement, Collection<JetModifierKeywordToken>> INCOMPATIBLE_MODIFIERS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, JetModifierKeywordToken> ILLEGAL_MODIFIER = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, JetModifierKeywordToken> REPEATED_MODIFIER = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, JetModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> INAPPLICABLE_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
+1
@@ -146,6 +146,7 @@ public class DefaultErrorMessages {
|
||||
}
|
||||
});
|
||||
MAP.put(ILLEGAL_MODIFIER, "Illegal modifier ''{0}''", TO_STRING);
|
||||
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
|
||||
MAP.put(INAPPLICABLE_ANNOTATION, "This annotation is not applicable to class members");
|
||||
|
||||
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
|
||||
|
||||
@@ -267,6 +267,7 @@ public class DeclarationsChecker {
|
||||
|
||||
private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
|
||||
checkOpenMembers(classDescriptor);
|
||||
checkConstructorParameters(aClass);
|
||||
if (c.getTopDownAnalysisParameters().isLazy()) {
|
||||
checkTypeParameters(aClass);
|
||||
}
|
||||
@@ -289,6 +290,15 @@ public class DeclarationsChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkConstructorParameters(JetClass aClass) {
|
||||
for (JetParameter parameter : aClass.getPrimaryConstructorParameters()) {
|
||||
PropertyDescriptor propertyDescriptor = trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
|
||||
if (propertyDescriptor != null) {
|
||||
modifiersChecker.checkModifiersForDeclaration(parameter, propertyDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTypeParameters(JetTypeParameterListOwner typeParameterListOwner) {
|
||||
// TODO: Support annotation for type parameters
|
||||
for (JetTypeParameter jetTypeParameter : typeParameterListOwner.getTypeParameters()) {
|
||||
@@ -514,6 +524,9 @@ public class DeclarationsChecker {
|
||||
|
||||
private void checkAccessors(@NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
for (JetPropertyAccessor accessor : property.getAccessors()) {
|
||||
PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
|
||||
assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText();
|
||||
modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor);
|
||||
modifiersChecker.checkIllegalModalityModifiers(accessor);
|
||||
}
|
||||
JetPropertyAccessor getter = property.getGetter();
|
||||
|
||||
@@ -33,11 +33,9 @@ import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lexer.JetTokens.*;
|
||||
@@ -65,6 +63,62 @@ public class ModifiersChecker {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkIncompatibleModifiers(
|
||||
@Nullable JetModifierList modifierList,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull Collection<JetModifierKeywordToken> availableModifiers,
|
||||
@NotNull Collection<JetModifierKeywordToken>... availableCombinations
|
||||
) {
|
||||
if (modifierList == null) return;
|
||||
Collection<JetModifierKeywordToken> presentModifiers = Sets.newLinkedHashSet();
|
||||
for (JetModifierKeywordToken modifier : availableModifiers) {
|
||||
if (modifierList.hasModifier(modifier)) {
|
||||
presentModifiers.add(modifier);
|
||||
}
|
||||
}
|
||||
checkRepeatedModifiers(modifierList, trace, availableModifiers);
|
||||
|
||||
if (presentModifiers.size() == 1) {
|
||||
return;
|
||||
}
|
||||
for (Collection<JetModifierKeywordToken> combination : availableCombinations) {
|
||||
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (JetModifierKeywordToken token : presentModifiers) {
|
||||
trace.report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token).getPsi(), presentModifiers));
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkRepeatedModifiers(
|
||||
@NotNull JetModifierList modifierList,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull Collection<JetModifierKeywordToken> availableModifiers
|
||||
) {
|
||||
for (JetModifierKeywordToken token : availableModifiers) {
|
||||
if (!modifierList.hasModifier(token)) continue;
|
||||
|
||||
List<ASTNode> nodesOfRepeatedTokens = Lists.newArrayList();
|
||||
ASTNode node = modifierList.getNode().getFirstChildNode();
|
||||
while (node != null) {
|
||||
if (node.getElementType() == token) {
|
||||
nodesOfRepeatedTokens.add(node);
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
if (nodesOfRepeatedTokens.size() > 1) {
|
||||
for (ASTNode repeatedToken : nodesOfRepeatedTokens) {
|
||||
trace.report(REPEATED_MODIFIER.on(repeatedToken.getPsi(), token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkIncompatibleVarianceModifiers(@Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
|
||||
checkIncompatibleModifiers(modifierList, trace, Arrays.asList(JetTokens.IN_KEYWORD, JetTokens.OUT_KEYWORD));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final BindingTrace trace;
|
||||
@NotNull
|
||||
@@ -87,6 +141,7 @@ public class ModifiersChecker {
|
||||
checkInnerModifier(modifierListOwner, descriptor);
|
||||
checkModalityModifiers(modifierListOwner);
|
||||
checkVisibilityModifiers(modifierListOwner, descriptor);
|
||||
checkVarianceModifiersOfTypeParameters(modifierListOwner);
|
||||
}
|
||||
checkPlatformNameApplicability(descriptor);
|
||||
runAnnotationCheckers(modifierListOwner, descriptor);
|
||||
@@ -172,16 +227,6 @@ public class ModifiersChecker {
|
||||
}
|
||||
|
||||
private void checkPlatformNameApplicability(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
if (propertyDescriptor.getGetter() != null) {
|
||||
checkPlatformNameApplicability(propertyDescriptor.getGetter());
|
||||
}
|
||||
if (propertyDescriptor.getSetter() != null) {
|
||||
checkPlatformNameApplicability(propertyDescriptor.getSetter());
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(new FqName("kotlin.platform.platformName"));
|
||||
if (annotation == null) return;
|
||||
|
||||
@@ -205,24 +250,7 @@ public class ModifiersChecker {
|
||||
}
|
||||
|
||||
private void checkCompatibility(@Nullable JetModifierList modifierList, Collection<JetModifierKeywordToken> availableModifiers, Collection<JetModifierKeywordToken>... availableCombinations) {
|
||||
if (modifierList == null) return;
|
||||
Collection<JetModifierKeywordToken> presentModifiers = Sets.newLinkedHashSet();
|
||||
for (JetModifierKeywordToken modifier : availableModifiers) {
|
||||
if (modifierList.hasModifier(modifier)) {
|
||||
presentModifiers.add(modifier);
|
||||
}
|
||||
}
|
||||
if (presentModifiers.size() == 1) {
|
||||
return;
|
||||
}
|
||||
for (Collection<JetModifierKeywordToken> combination : availableCombinations) {
|
||||
if (presentModifiers.containsAll(combination) && combination.containsAll(presentModifiers)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (JetModifierKeywordToken token : presentModifiers) {
|
||||
trace.report(Errors.INCOMPATIBLE_MODIFIERS.on(modifierList.getModifierNode(token).getPsi(), presentModifiers));
|
||||
}
|
||||
checkIncompatibleModifiers(modifierList, trace, availableModifiers, availableCombinations);
|
||||
}
|
||||
|
||||
private void checkRedundantModifier(@NotNull JetModifierList modifierList, Pair<JetModifierKeywordToken, JetModifierKeywordToken>... redundantBundles) {
|
||||
@@ -317,4 +345,13 @@ public class ModifiersChecker {
|
||||
checker.check(declaration, descriptor, trace);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkVarianceModifiersOfTypeParameters(@NotNull JetModifierListOwner modifierListOwner) {
|
||||
if (!(modifierListOwner instanceof JetTypeParameterListOwner)) return;
|
||||
List<JetTypeParameter> typeParameters = ((JetTypeParameterListOwner) modifierListOwner).getTypeParameters();
|
||||
for (JetTypeParameter typeParameter : typeParameters) {
|
||||
JetModifierList modifierList = typeParameter.getModifierList();
|
||||
checkIncompatibleVarianceModifiers(modifierList, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.jet.context.LazinessToken
|
||||
import org.jetbrains.jet.lang.resolve.lazy.LazyEntity
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.jet.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.jet.lexer.JetTokens
|
||||
|
||||
public class TypeResolver(
|
||||
private val annotationResolver: AnnotationResolver,
|
||||
@@ -256,6 +257,7 @@ public class TypeResolver(
|
||||
val (i, argumentElement) = it
|
||||
|
||||
val projectionKind = argumentElement.getProjectionKind()
|
||||
ModifiersChecker.checkIncompatibleVarianceModifiers(argumentElement.getModifierList(), c.trace)
|
||||
if (projectionKind == JetProjectionKind.STAR) {
|
||||
val parameters = constructor.getParameters()
|
||||
if (parameters.size() > i) {
|
||||
|
||||
@@ -125,6 +125,7 @@ public class CandidateResolver {
|
||||
for (JetTypeProjection projection : jetTypeArguments) {
|
||||
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||
ModifiersChecker.checkIncompatibleVarianceModifiers(projection.getModifierList(), context.trace);
|
||||
}
|
||||
JetType type = argumentTypeResolver.resolveTypeRefWithDefault(
|
||||
projection.getTypeReference(), context.scope, context.trace,
|
||||
|
||||
Reference in New Issue
Block a user