Redundant modifier targets introduced (abstract / open on interface, final on enum or object)
This commit is contained in:
@@ -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);
|
||||
|
||||
+1
-3
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user