[FIR] KT-54507 Report REDUNDANT_MODALITY_MODIFIER for open interface
- `REDUNDANT_MODIFIER_FOR_TARGET` is already reported for `open` interfaces, but for consistency and IDE support, the compiler now reports `REDUNDANT_MODALITY_MODIFIER` as well via the extended checker. - `REDUNDANT_MODIFIER_FOR_TARGET` cannot be disabled for this case because it's reported via a basic checker while `REDUNDANT_MODALITY_MODIFIER` is reported via an extended checker. - Rename `implicitModality` to `redundantModalities` and return a set of modalities. The idea of a *single* implicit/redundant modality doesn't stand up to scrutiny. For example, for interfaces with `ABSTRACT` implicit modality, `OPEN` is also a redundant modifier. But this is not necessarily the case for all kinds of declarations. Hypothetically, if it was possible to declare a class that is abstract by default, adding an `open` modifier to that class would not be redundant, as it would make the class instantiable.
This commit is contained in:
committed by
Space Team
parent
76ca96d2e2
commit
5909b191a5
+2
@@ -18,6 +18,8 @@ FILE: RedundantModalityModifierChecker.kt
|
||||
|
||||
private final fun bar(): R|kotlin/Unit|
|
||||
|
||||
public abstract fun loo(): R|kotlin/Unit|
|
||||
|
||||
public open fun goo(): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -12,6 +12,7 @@ interface Interface {
|
||||
// error
|
||||
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> <!WRONG_MODIFIER_CONTAINING_DECLARATION!>final<!> fun bar()
|
||||
|
||||
<!REDUNDANT_MODALITY_MODIFIER, REDUNDANT_OPEN_IN_INTERFACE!>open<!> fun loo()
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>open<!> fun goo() {}
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun tar()
|
||||
|
||||
@@ -84,7 +85,7 @@ abstract class AbstractDerived2 : Interface {
|
||||
// Redundant final object
|
||||
<!REDUNDANT_MODALITY_MODIFIER!>final<!> object FinalObject
|
||||
// Open interface
|
||||
<!REDUNDANT_MODIFIER_FOR_TARGET!>open<!> interface OpenInterface
|
||||
<!REDUNDANT_MODALITY_MODIFIER, REDUNDANT_MODIFIER_FOR_TARGET!>open<!> interface OpenInterface
|
||||
|
||||
class FinalDerived2(override <!REDUNDANT_MODALITY_MODIFIER!>final<!> val gav: Int) : Base() {
|
||||
override fun bar() {}
|
||||
|
||||
@@ -221,25 +221,26 @@ fun FirClass.modality(): Modality? {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns implicit modality by FirMemberDeclaration<*>
|
||||
* Returns a set of [Modality] modifiers which are redundant for the given [FirMemberDeclaration]. If a modality modifier is redundant, the
|
||||
* declaration's modality won't be changed by the modifier.
|
||||
*/
|
||||
fun FirMemberDeclaration.implicitModality(context: CheckerContext): Modality {
|
||||
fun FirMemberDeclaration.redundantModalities(context: CheckerContext): Set<Modality> {
|
||||
if (this is FirRegularClass) {
|
||||
return when (classKind) {
|
||||
ClassKind.INTERFACE -> Modality.ABSTRACT
|
||||
else -> Modality.FINAL
|
||||
ClassKind.INTERFACE -> setOf(Modality.ABSTRACT, Modality.OPEN)
|
||||
else -> setOf(Modality.FINAL)
|
||||
}
|
||||
}
|
||||
|
||||
val containingClass = context.findClosestClassOrObject() ?: return Modality.FINAL
|
||||
val containingClass = context.findClosestClassOrObject() ?: return setOf(Modality.FINAL)
|
||||
|
||||
return when {
|
||||
isOverride && !containingClass.isFinal -> Modality.OPEN
|
||||
isOverride && !containingClass.isFinal -> setOf(Modality.OPEN)
|
||||
containingClass.isInterface -> when {
|
||||
hasBody() -> Modality.OPEN
|
||||
else -> Modality.ABSTRACT
|
||||
hasBody() -> setOf(Modality.OPEN)
|
||||
else -> setOf(Modality.ABSTRACT, Modality.OPEN)
|
||||
}
|
||||
else -> Modality.FINAL
|
||||
else -> setOf(Modality.FINAL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -10,13 +10,13 @@ import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.implicitModality
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDeclarationSyntaxChecker
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
|
||||
import org.jetbrains.kotlin.diagnostics.modalityModifier
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.redundantModalities
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDeclarationSyntaxChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
@@ -46,8 +46,8 @@ object RedundantModalityModifierSyntaxChecker : FirDeclarationSyntaxChecker<FirD
|
||||
) return
|
||||
|
||||
if (source.treeStructure.modalityModifier(source.lighterASTNode) == null) return
|
||||
val implicitModality = element.implicitModality(context)
|
||||
if (modality == implicitModality) {
|
||||
val redundantModalities = element.redundantModalities(context)
|
||||
if (redundantModalities.contains(modality)) {
|
||||
reporter.reportOn(source, REDUNDANT_MODALITY_MODIFIER, context)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user