Redundant modifier targets introduced (abstract / open on interface, final on enum or object)

This commit is contained in:
Mikhail Glukhikh
2015-07-31 18:34:12 +03:00
parent d127162a6d
commit 992c019c1e
8 changed files with 94 additions and 11 deletions
@@ -112,6 +112,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, JetModifierKeywordToken> REPEATED_MODIFIER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, JetModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, String> WRONG_MODIFIER_TARGET = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, String> REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, String> WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PLATFORM_NAME = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<JetAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
@@ -25,8 +25,6 @@ import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.JetKeywordToken;
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetSimpleNameExpression;
import org.jetbrains.kotlin.psi.JetTypeConstraint;
@@ -42,7 +40,6 @@ import org.jetbrains.kotlin.util.MappedExtensionProvider;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
@@ -122,6 +119,7 @@ public class DefaultErrorMessages {
MAP.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING);
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
MAP.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, TO_STRING);
MAP.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, TO_STRING);
MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(INAPPLICABLE_PLATFORM_NAME, "platformName annotation is not applicable to this declaration");
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
@@ -39,9 +39,9 @@ public object ModifierCheckerCore {
private val possibleTargetMap = mapOf<JetModifierKeywordToken, Set<KotlinTarget>>(
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
ABSTRACT_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, MEMBER_PROPERTY, MEMBER_FUNCTION),
OPEN_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, MEMBER_PROPERTY, MEMBER_FUNCTION),
FINAL_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, MEMBER_PROPERTY, MEMBER_FUNCTION),
ABSTRACT_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
OPEN_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
FINAL_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
SEALED_KEYWORD to EnumSet.of(CLASS, LOCAL_CLASS, INNER_CLASS),
INNER_KEYWORD to EnumSet.of(INNER_CLASS),
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
@@ -60,6 +60,13 @@ public object ModifierCheckerCore {
COMPANION_KEYWORD to EnumSet.of(OBJECT)
)
// NOTE: redundant targets must be possible!
private val redundantTargetMap = mapOf<JetModifierKeywordToken, Set<KotlinTarget>>(
ABSTRACT_KEYWORD to EnumSet.of(INTERFACE),
OPEN_KEYWORD to EnumSet.of(INTERFACE),
FINAL_KEYWORD to EnumSet.of(ENUM_CLASS, OBJECT)
)
private val possibleParentTargetMap = mapOf<JetModifierKeywordToken, Set<KotlinTarget>>(
INNER_KEYWORD to EnumSet.of(CLASS, INNER_CLASS, LOCAL_CLASS, ENUM_CLASS, ENUM_ENTRY),
OVERRIDE_KEYWORD to EnumSet.of(CLASSIFIER, ENUM_ENTRY),
@@ -146,9 +153,15 @@ public object ModifierCheckerCore {
private fun checkTarget(trace: BindingTrace, node: ASTNode, actualTargets: List<KotlinTarget>): Boolean {
val modifier = node.elementType as JetModifierKeywordToken
val possibleTargets = possibleTargetMap[modifier] ?: emptySet()
if (actualTargets.any { it in possibleTargets }) return true
trace.report(Errors.WRONG_MODIFIER_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
return false
if (!actualTargets.any { it in possibleTargets }) {
trace.report(Errors.WRONG_MODIFIER_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
return false
}
val redundantTargets = redundantTargetMap[modifier] ?: emptySet()
if (actualTargets.any { it in redundantTargets}) {
trace.report(Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
}
return true
}
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?): Boolean {
@@ -6,13 +6,13 @@
<!WRONG_MODIFIER_TARGET!>override<!> companion object {}
<!WRONG_MODIFIER_TARGET!>open<!> companion object {}
<!WRONG_MODIFIER_TARGET!>abstract<!> companion object {}
<!WRONG_MODIFIER_TARGET!>final<!> companion object {}
<!REDUNDANT_MODIFIER_FOR_TARGET!>final<!> companion object {}
}
<!WRONG_MODIFIER_TARGET!>override<!> object B1 {}
<!WRONG_MODIFIER_TARGET!>open<!> object B2 {}
<!WRONG_MODIFIER_TARGET!>abstract<!> object B3 {}
<!WRONG_MODIFIER_TARGET!>final<!> object B4 {}
<!REDUNDANT_MODIFIER_FOR_TARGET!>final<!> object B4 {}
<!WRONG_MODIFIER_TARGET!>override<!> enum class C {}
<!WRONG_MODIFIER_TARGET!>override<!> interface D {}
@@ -0,0 +1,10 @@
<!REDUNDANT_MODIFIER_FOR_TARGET!>open<!> interface First
<!REDUNDANT_MODIFIER_FOR_TARGET!>abstract<!> interface Second
<!REDUNDANT_MODIFIER_FOR_TARGET!>final<!> enum class Third {
FOURTH,
FIFTH
}
<!REDUNDANT_MODIFIER_FOR_TARGET!>final<!> object Sixth
@@ -0,0 +1,54 @@
package
internal interface First {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal interface Second {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal object Sixth {
private constructor Sixth()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final enum class Third : kotlin.Enum<Third> {
public enum entry FOURTH : Third {
private constructor FOURTH()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Third): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public enum entry FIFTH : Third {
private constructor FIFTH()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Third): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
private constructor Third()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Third): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final override /*1*/ /*fake_override*/ fun name(): kotlin.String
public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Third
public final /*synthesized*/ fun values(): kotlin.Array<Third>
}
@@ -8850,6 +8850,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("redundantTargets.kt")
public void testRedundantTargets() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/redundantTargets.kt");
doTest(fileName);
}
@TestMetadata("repeatedModifiers.kt")
public void testRepeatedModifiers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/repeatedModifiers.kt");
@@ -113,6 +113,7 @@ public class QuickFixRegistrar : QuickFixContributor {
GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.registerFactory(removeModifierFactory)
REDUNDANT_MODIFIER_IN_GETTER.registerFactory(removeRedundantModifierFactory)
WRONG_MODIFIER_TARGET.registerFactory(removeModifierFactory)
REDUNDANT_MODIFIER_FOR_TARGET.registerFactory(removeModifierFactory)
WRONG_MODIFIER_CONTAINING_DECLARATION.registerFactory(removeModifierFactory)
REPEATED_MODIFIER.registerFactory(removeModifierFactory)