Added check for incompatible variance modifiers and repeated modifiers

This commit is contained in:
Svetlana Isakova
2014-12-19 17:37:22 +03:00
parent d2becce1ac
commit 7b09e85717
38 changed files with 310 additions and 79 deletions
@@ -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);
@@ -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,