[FIR] Part 5. Introduce paired common checkers for expect classes

There are some cases when we want to run some platform checker not from
  platform session but from common session. All such cases appear when
  we check some `expect` class

```kotlin
// MODULE: common
expect interface A
expect class B : A

class C : A

// MODULE: platform()()(common)
actual interface A {
    fun foo()
}

actual class B : A {
    override fun foo() {}
}
```

In this example we want to report "abstract foo not implemented" on
  class `C`, but we don't want to report it on `expect class B` (as
  its supertype is always `expect A`, never `actual A`)

So to cover such cases some platform checkers were split into two parts:
- `Regular`, which is platform checkers and runs for everything except
  expect declaration
- `ForExpectClass`, which is common checkers and runs only for expect
  declarations

^KT-58881 Fixed
^KT-58881 Fixed
^KT-64187 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-01-09 15:12:05 +02:00
committed by Nikolay Lunyak
parent f5d8113de3
commit 990da9fa1a
27 changed files with 495 additions and 156 deletions
@@ -12,7 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsEx
object JsDeclarationCheckers : DeclarationCheckers() { object JsDeclarationCheckers : DeclarationCheckers() {
override val functionCheckers: Set<FirFunctionChecker> override val functionCheckers: Set<FirFunctionChecker>
get() = setOf( get() = setOf(
FirJsInheritanceFunctionChecker, FirJsInheritanceFunctionChecker.Regular,
FirJsInheritanceFunctionChecker.ForExpectClass,
) )
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker> override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
@@ -30,11 +31,15 @@ object JsDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker> override val classCheckers: Set<FirClassChecker>
get() = setOf( get() = setOf(
FirJsMultipleInheritanceChecker, FirJsMultipleInheritanceChecker.Regular,
FirJsMultipleInheritanceChecker.ForExpectClass,
FirJsDynamicDeclarationChecker, FirJsDynamicDeclarationChecker,
FirJsInheritanceClassChecker, FirJsInheritanceClassChecker.Regular,
FirJsExternalInheritorOnlyChecker, FirJsInheritanceClassChecker.ForExpectClass,
FirJsNameClashClassMembersChecker FirJsExternalInheritorOnlyChecker.Regular,
FirJsExternalInheritorOnlyChecker.ForExpectClass,
FirJsNameClashClassMembersChecker.Regular,
FirJsNameClashClassMembersChecker.ForExpectClass,
) )
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker> override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.hasAnnotation import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeClassLikeType
@@ -21,8 +22,21 @@ import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalInheritorsOnly import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalInheritorsOnly
import org.jetbrains.kotlin.utils.addToStdlib.popLast import org.jetbrains.kotlin.utils.addToStdlib.popLast
// TODO: extract common checker for expect interfaces sealed class FirJsExternalInheritorOnlyChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirJsExternalInheritorOnlyChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirJsExternalInheritorOnlyChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirJsExternalInheritorOnlyChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
private fun FirClass.forEachParents(context: CheckerContext, f: (FirRegularClassSymbol) -> Unit) { private fun FirClass.forEachParents(context: CheckerContext, f: (FirRegularClassSymbol) -> Unit) {
val todo = superConeTypes.toMutableList() val todo = superConeTypes.toMutableList()
val done = hashSetOf<FirRegularClassSymbol>() val done = hashSetOf<FirRegularClassSymbol>()
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol
@@ -26,8 +27,21 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType
import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.fir.types.typeContext
// TODO: extract common checker for expect interfaces sealed class FirJsInheritanceClassChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirJsInheritanceClassChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirJsInheritanceClassChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirJsInheritanceClassChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.symbol.isEffectivelyExternal(context)) { if (!declaration.symbol.isEffectivelyExternal(context)) {
val fakeOverriddenMethod = declaration.findFakeMethodOverridingExternalWithOptionalParams(context) val fakeOverriddenMethod = declaration.findFakeMethodOverridingExternalWithOptionalParams(context)
@@ -13,11 +13,26 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams import org.jetbrains.kotlin.fir.analysis.js.checkers.isOverridingExternalWithOptionalParams
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
sealed class FirJsInheritanceFunctionChecker(mppKind: MppCheckerKind) : FirFunctionChecker(mppKind) {
object Regular : FirJsInheritanceFunctionChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if ((context.containingDeclarations.last() as? FirClass)?.isExpect == true) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirJsInheritanceFunctionChecker(MppCheckerKind.Common) {
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if ((context.containingDeclarations.last() as? FirClass)?.isExpect != true) return
super.check(declaration, context, reporter)
}
}
// TODO: extract common checker for expect interfaces
object FirJsInheritanceFunctionChecker : FirFunctionChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isNotEffectivelyExternalFunctionButOverridesExternal(context)) { if (declaration.isNotEffectivelyExternalFunctionButOverridesExternal(context)) {
reporter.reportOn(declaration.source, FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, context) reporter.reportOn(declaration.source, FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, context)
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.overriddenFunctions
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.scopes.getFunctions import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
@@ -23,8 +24,21 @@ import org.jetbrains.kotlin.fir.types.isSubtypeOf
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
// TODO: extract common checker for expect interfaces sealed class FirJsMultipleInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirJsMultipleInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirJsMultipleInheritanceChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirJsMultipleInheritanceChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.checkFunctionIfSubtypeOf( declaration.checkFunctionIfSubtypeOf(
functionToCheck = OperatorNameConventions.GET, functionToCheck = OperatorNameConventions.GET,
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.constructors import org.jetbrains.kotlin.fir.declarations.constructors
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isFinal import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -31,8 +32,21 @@ import org.jetbrains.kotlin.fir.unwrapFakeOverridesOrDelegated
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.popLast import org.jetbrains.kotlin.utils.addToStdlib.popLast
// TODO: extract common checker for expect interfaces sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirJsNameClashClassMembersChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirJsNameClashClassMembersChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirJsNameClashClassMembersChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
private class StableNamesCollector { private class StableNamesCollector {
val jsStableNames = mutableSetOf<FirJsStableName>() val jsStableNames = mutableSetOf<FirJsStableName>()
val overrideIntersections = hashMapOf<FirCallableSymbol<*>, HashSet<FirCallableSymbol<*>>>() val overrideIntersections = hashMapOf<FirCallableSymbol<*>, HashSet<FirCallableSymbol<*>>>()
@@ -24,7 +24,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker> override val classCheckers: Set<FirClassChecker>
get() = setOf( get() = setOf(
FirStrictfpApplicabilityChecker, FirStrictfpApplicabilityChecker,
FirOverrideJavaNullabilityWarningChecker, FirOverrideJavaNullabilityWarningChecker.Regular,
FirOverrideJavaNullabilityWarningChecker.ForExpectClass,
) )
override val regularClassCheckers: Set<FirRegularClassChecker> override val regularClassCheckers: Set<FirRegularClassChecker>
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAbstractOverrid
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.java.enhancement.EnhancedForWarningConeSubstitutor import org.jetbrains.kotlin.fir.java.enhancement.EnhancedForWarningConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
@@ -24,8 +25,21 @@ import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
// TODO: extract common checker for expect interfaces sealed class FirOverrideJavaNullabilityWarningChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) {
object FirOverrideJavaNullabilityWarningChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) { object Regular : FirOverrideJavaNullabilityWarningChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirOverrideJavaNullabilityWarningChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext) val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext)
val scope = declaration.unsubstitutedScope(context) val scope = declaration.unsubstitutedScope(context)
@@ -14,14 +14,33 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
object FirNativeObjCNameCallableChecker : FirCallableDeclarationChecker(MppCheckerKind.Common) { sealed class FirNativeObjCNameCallableChecker(mppKind: MppCheckerKind) : FirCallableDeclarationChecker(mppKind) {
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { object Regular : FirNativeObjCNameCallableChecker(MppCheckerKind.Platform) {
if (declaration !is FirSimpleFunction && declaration !is FirProperty) return override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return
if (containingClass != null) { if (containingClass.isExpect) return
val firTypeScope = containingClass.unsubstitutedScope(context) check(declaration, containingClass, context, reporter)
FirNativeObjCNameUtilities.checkCallableMember(firTypeScope, declaration.symbol, declaration, context, reporter)
} }
} }
object ForExpectClass : FirNativeObjCNameCallableChecker(MppCheckerKind.Common) {
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass ?: return
if (!containingClass.isExpect) return
check(declaration, containingClass, context, reporter)
}
}
protected fun check(
declaration: FirCallableDeclaration,
containingClass: FirClass,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
if (declaration !is FirSimpleFunction && declaration !is FirProperty) return
val firTypeScope = containingClass.unsubstitutedScope(context)
FirNativeObjCNameUtilities.checkCallableMember(firTypeScope, declaration.symbol, declaration, context, reporter)
}
} }
@@ -12,11 +12,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameUtilities.checkCallableMember import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameUtilities.checkCallableMember
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.isIntersectionOverride import org.jetbrains.kotlin.fir.isIntersectionOverride
import org.jetbrains.kotlin.fir.scopes.processAllFunctions import org.jetbrains.kotlin.fir.scopes.processAllFunctions
import org.jetbrains.kotlin.fir.scopes.processAllProperties import org.jetbrains.kotlin.fir.scopes.processAllProperties
object FirNativeObjCNameOverridesChecker : FirClassChecker(MppCheckerKind.Platform) { sealed class FirNativeObjCNameOverridesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object Regular : FirNativeObjCNameOverridesChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirNativeObjCNameOverridesChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
// We just need to check intersection overrides, all other declarations are checked by FirNativeObjCNameChecker // We just need to check intersection overrides, all other declarations are checked by FirNativeObjCNameChecker
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirCallableDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirCallableDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT
import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCRefinementOverridesChecker.check
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
@@ -35,7 +34,15 @@ object FirNativeObjCRefinementChecker : FirCallableDeclarationChecker(MppChecker
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass val containingClass = context.containingDeclarations.lastOrNull() as? FirClass
if (containingClass != null) { if (containingClass != null) {
val firTypeScope = containingClass.unsubstitutedScope(context) val firTypeScope = containingClass.unsubstitutedScope(context)
check(firTypeScope, declaration.symbol, declaration, context, reporter, objCAnnotations, swiftAnnotations) FirNativeObjCRefinementOverridesChecker.check(
firTypeScope,
declaration.symbol,
declaration,
context,
reporter,
objCAnnotations,
swiftAnnotations
)
} }
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeSymbol import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeSymbol
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.isIntersectionOverride import org.jetbrains.kotlin.fir.isIntersectionOverride
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
@@ -29,8 +30,20 @@ import org.jetbrains.kotlin.fir.scopes.processAllFunctions
import org.jetbrains.kotlin.fir.scopes.processAllProperties import org.jetbrains.kotlin.fir.scopes.processAllProperties
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
// TODO: extract common checker for expect interfaces sealed class FirNativeObjCRefinementOverridesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirNativeObjCRefinementOverridesChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirNativeObjCRefinementOverridesChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
// We just need to check intersection overrides, all other declarations are checked by FirNativeObjCRefinementChecker // We just need to check intersection overrides, all other declarations are checked by FirNativeObjCRefinementChecker
@@ -45,80 +58,83 @@ object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind.
} }
} }
fun check( companion object {
baseScope: FirTypeScope, fun check(
memberSymbol: FirCallableSymbol<*>, baseScope: FirTypeScope,
declarationToReport: FirDeclaration, memberSymbol: FirCallableSymbol<*>,
context: CheckerContext, declarationToReport: FirDeclaration,
reporter: DiagnosticReporter, context: CheckerContext,
objCAnnotations: List<FirAnnotation>, reporter: DiagnosticReporter,
swiftAnnotations: List<FirAnnotation> objCAnnotations: List<FirAnnotation>,
) { swiftAnnotations: List<FirAnnotation>
val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol) ) {
if (overriddenMemberSymbols.isEmpty()) return val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol)
var isHiddenFromObjC = objCAnnotations.isNotEmpty() if (overriddenMemberSymbols.isEmpty()) return
var isRefinedInSwift = swiftAnnotations.isNotEmpty() var isHiddenFromObjC = objCAnnotations.isNotEmpty()
val supersNotHiddenFromObjC = mutableListOf<FirCallableSymbol<*>>() var isRefinedInSwift = swiftAnnotations.isNotEmpty()
val supersNotRefinedInSwift = mutableListOf<FirCallableSymbol<*>>() val supersNotHiddenFromObjC = mutableListOf<FirCallableSymbol<*>>()
for ((symbol, scope) in overriddenMemberSymbols) { val supersNotRefinedInSwift = mutableListOf<FirCallableSymbol<*>>()
val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope) for ((symbol, scope) in overriddenMemberSymbols) {
if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol) val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope)
if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol) if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol)
if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol)
}
if (isHiddenFromObjC && supersNotHiddenFromObjC.isNotEmpty()) {
reporter.reportIncompatibleOverride(declarationToReport, objCAnnotations, supersNotHiddenFromObjC, context)
}
if (isRefinedInSwift && supersNotRefinedInSwift.isNotEmpty()) {
reporter.reportIncompatibleOverride(declarationToReport, swiftAnnotations, supersNotRefinedInSwift, context)
}
} }
if (isHiddenFromObjC && supersNotHiddenFromObjC.isNotEmpty()) {
reporter.reportIncompatibleOverride(declarationToReport, objCAnnotations, supersNotHiddenFromObjC, context) private fun FirCallableSymbol<*>.inheritsRefinedAnnotations(session: FirSession, baseScope: FirTypeScope): Pair<Boolean, Boolean> {
val (hasObjC, hasSwift) = hasRefinedAnnotations(session)
if (hasObjC && hasSwift) return true to true
// Note: `checkMember` requires all overridden symbols to be either refined or not refined.
val (overriddenMemberSymbol, scope) = baseScope.getDirectOverriddenMembersWithBaseScope(this).firstOrNull()
?: return hasObjC to hasSwift
val (inheritsObjC, inheritsSwift) = overriddenMemberSymbol.inheritsRefinedAnnotations(session, scope)
return (hasObjC || inheritsObjC) to (hasSwift || inheritsSwift)
} }
if (isRefinedInSwift && supersNotRefinedInSwift.isNotEmpty()) {
reporter.reportIncompatibleOverride(declarationToReport, swiftAnnotations, supersNotRefinedInSwift, context)
}
}
private fun FirCallableSymbol<*>.inheritsRefinedAnnotations(session: FirSession, baseScope: FirTypeScope): Pair<Boolean, Boolean> { private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair<Boolean, Boolean> {
val (hasObjC, hasSwift) = hasRefinedAnnotations(session) var hasObjC = false
if (hasObjC && hasSwift) return true to true var hasSwift = false
// Note: `checkMember` requires all overridden symbols to be either refined or not refined. for (annotation in resolvedAnnotationsWithClassIds) {
val (overriddenMemberSymbol, scope) = baseScope.getDirectOverriddenMembersWithBaseScope(this).firstOrNull() val metaAnnotations = annotation.toAnnotationClassLikeSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty()
?: return hasObjC to hasSwift for (metaAnnotation in metaAnnotations) {
val (inheritsObjC, inheritsSwift) = overriddenMemberSymbol.inheritsRefinedAnnotations(session, scope) when (metaAnnotation.toAnnotationClassId(session)) {
return (hasObjC || inheritsObjC) to (hasSwift || inheritsSwift) hidesFromObjCClassId -> {
} hasObjC = true
break
}
private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair<Boolean, Boolean> { refinesInSwiftClassId -> {
var hasObjC = false hasSwift = true
var hasSwift = false break
for (annotation in resolvedAnnotationsWithClassIds) { }
val metaAnnotations = annotation.toAnnotationClassLikeSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty()
for (metaAnnotation in metaAnnotations) {
when (metaAnnotation.toAnnotationClassId(session)) {
hidesFromObjCClassId -> {
hasObjC = true
break
}
refinesInSwiftClassId -> {
hasSwift = true
break
} }
} }
if (hasObjC && hasSwift) return true to true
} }
if (hasObjC && hasSwift) return true to true return hasObjC to hasSwift
} }
return hasObjC to hasSwift
}
private fun DiagnosticReporter.reportIncompatibleOverride( private fun DiagnosticReporter.reportIncompatibleOverride(
declaration: FirDeclaration, declaration: FirDeclaration,
annotations: List<FirAnnotation>, annotations: List<FirAnnotation>,
notRefinedSupers: List<FirCallableSymbol<*>>, notRefinedSupers: List<FirCallableSymbol<*>>,
context: CheckerContext context: CheckerContext
) { ) {
val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) } val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) }
if (annotations.isEmpty()) { if (annotations.isEmpty()) {
reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
} else { } else {
for (annotation in annotations) { for (annotation in annotations) {
reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context) reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
}
} }
} }
} }
} }
@@ -18,8 +18,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.references.isError import org.jetbrains.kotlin.fir.references.isError
@@ -34,19 +36,34 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME
// TODO: extract common checker for expect interfaces sealed class FirNativeThrowsChecker(mppKind: MppCheckerKind) : FirBasicDeclarationChecker(mppKind) {
object FirNativeThrowsChecker : FirBasicDeclarationChecker(MppCheckerKind.Platform) { object Regular : FirNativeThrowsChecker(MppCheckerKind.Platform) {
private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME) override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if ((declaration as? FirMemberDeclaration)?.isExpect == true) return
super.check(declaration, context, reporter)
}
}
private val cancellationExceptionFqName = FqName("kotlin.coroutines.cancellation.CancellationException") object ForExpectClass : FirNativeThrowsChecker(MppCheckerKind.Common) {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if ((declaration as? FirMemberDeclaration)?.isExpect != true) return
super.check(declaration, context, reporter)
}
}
private val cancellationExceptionAndSupersClassIds = setOf( companion object {
ClassId.topLevel(StandardNames.FqNames.throwable), private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME)
ClassId.topLevel(FqName("kotlin.Exception")),
ClassId.topLevel(FqName("kotlin.RuntimeException")), private val cancellationExceptionFqName = FqName("kotlin.coroutines.cancellation.CancellationException")
ClassId.topLevel(FqName("kotlin.IllegalStateException")),
ClassId.topLevel(cancellationExceptionFqName) private val cancellationExceptionAndSupersClassIds = setOf(
) ClassId.topLevel(StandardNames.FqNames.throwable),
ClassId.topLevel(FqName("kotlin.Exception")),
ClassId.topLevel(FqName("kotlin.RuntimeException")),
ClassId.topLevel(FqName("kotlin.IllegalStateException")),
ClassId.topLevel(cancellationExceptionFqName)
)
}
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
val throwsAnnotation = declaration.getAnnotationByClassId(throwsClassId, context.session) as? FirAnnotationCall val throwsAnnotation = declaration.getAnnotationByClassId(throwsClassId, context.session) as? FirAnnotationCall
@@ -10,7 +10,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
object NativeDeclarationCheckers : DeclarationCheckers() { object NativeDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker> override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
get() = setOf( get() = setOf(
FirNativeThrowsChecker, FirNativeThrowsChecker.Regular,
FirNativeThrowsChecker.ForExpectClass,
FirNativeSharedImmutableChecker, FirNativeSharedImmutableChecker,
FirNativeThreadLocalChecker, FirNativeThreadLocalChecker,
FirNativeIdentifierChecker, FirNativeIdentifierChecker,
@@ -20,13 +21,16 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker> override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker>
get() = setOf( get() = setOf(
FirNativeObjCRefinementChecker, FirNativeObjCRefinementChecker,
FirNativeObjCNameCallableChecker, FirNativeObjCNameCallableChecker.Regular,
FirNativeObjCNameCallableChecker.ForExpectClass,
) )
override val classCheckers: Set<FirClassChecker> override val classCheckers: Set<FirClassChecker>
get() = setOf( get() = setOf(
FirNativeObjCRefinementOverridesChecker, FirNativeObjCRefinementOverridesChecker.Regular,
FirNativeObjCNameOverridesChecker, FirNativeObjCRefinementOverridesChecker.ForExpectClass,
FirNativeObjCNameOverridesChecker.Regular,
FirNativeObjCNameOverridesChecker.ForExpectClass,
FirNativeObjCOutletChecker, FirNativeObjCOutletChecker,
FirNativeObjCActionChecker, FirNativeObjCActionChecker,
FirNativeObjCOverrideInitChecker, FirNativeObjCOverrideInitChecker,
@@ -5,14 +5,17 @@
package org.jetbrains.kotlin.fir.analysis.wasm.checkers package org.jetbrains.kotlin.fir.analysis.wasm.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsExportAnnotationChecker import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsExportAnnotationChecker
object WasmBaseDeclarationCheckers : DeclarationCheckers() { object WasmBaseDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker> override val classCheckers: Set<FirClassChecker>
get() = setOf( get() = setOf(
FirWasmExternalInheritanceChecker, FirWasmExternalInheritanceChecker.Regular,
FirWasmExternalInheritanceChecker.ForExpectClass,
) )
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker> override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
@@ -39,4 +42,4 @@ object WasmWasiDeclarationCheckers : DeclarationCheckers() {
get() = setOf( get() = setOf(
FirWasmWasiExternalDeclarationChecker, FirWasmWasiExternalDeclarationChecker,
) )
} }
@@ -15,11 +15,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
// TODO: extract common checker for expect interfaces sealed class FirWasmExternalInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirWasmExternalInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirWasmExternalInheritanceChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirWasmExternalInheritanceChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val session = context.session val session = context.session
val isCurrentClassExternal = declaration.symbol.isEffectivelyExternal(session) val isCurrentClassExternal = declaration.symbol.isEffectivelyExternal(session)
+27
View File
@@ -143,3 +143,30 @@ So the author of each new checker should decide in which session this checker sh
it most likely should be `Common` it most likely should be `Common`
- if the checker is interested in the scope of some type, it should be carefully considered how the actualization of the scope may affect - if the checker is interested in the scope of some type, it should be carefully considered how the actualization of the scope may affect
the checker the checker
#### Checkers for expect classes
```kotlin
// MODULE: common
expect interface A
expect class B : A
class C : A
// MODULE: platform()()(common)
actual interface A {
fun foo()
}
actual class B : A {
override fun foo() {}
}
```
In this example we want to report "abstract foo not implemented" on class `C`, but we don't want to report it on `expect class B` (as its supertype is always `expect A`, never `actual A`)
So to cover such cases, it's worth splitting the platform checker into two parts:
- `Regular`, which is platform checkers and runs for everything except `expect` declaration
- `ForExpectClass`, which is common checkers and runs only for `expect` declarations
As an example, check the implementation of [FirImplementationMismatchChecker](compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImplementationMismatchChecker.kt) checker
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFiniteBoundRestrictionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirInlinedLambdaNonSourceAnnotationsChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirInlinedLambdaNonSourceAnnotationsChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirMissingDependencySupertypeChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirMissingDependencySupertypeChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirSuspendAnonymousFunctionChecker import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirSuspendAnonymousFunctionChecker
@@ -103,15 +102,19 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker> override val classCheckers: Set<FirClassChecker>
get() = setOf( get() = setOf(
FirOverrideChecker, FirOverrideChecker.Regular,
FirNotImplementedOverrideChecker, FirOverrideChecker.ForExpectClass,
FirNotImplementedOverrideSimpleEnumEntryChecker, FirNotImplementedOverrideChecker.Regular,
FirNotImplementedOverrideChecker.ForExpectClass,
FirNotImplementedOverrideSimpleEnumEntryChecker.Regular,
FirNotImplementedOverrideSimpleEnumEntryChecker.ForExpectClass,
FirThrowableSubclassChecker, FirThrowableSubclassChecker,
FirOpenMemberChecker, FirOpenMemberChecker,
FirClassVarianceChecker, FirClassVarianceChecker,
FirSealedSupertypeChecker, FirSealedSupertypeChecker,
FirMemberPropertiesChecker, FirMemberPropertiesChecker,
FirImplementationMismatchChecker, FirImplementationMismatchChecker.Regular,
FirImplementationMismatchChecker.ForExpectClass,
FirTypeParametersInObjectChecker, FirTypeParametersInObjectChecker,
FirSupertypesChecker, FirSupertypesChecker,
FirPrimaryConstructorSuperTypeChecker, FirPrimaryConstructorSuperTypeChecker,
@@ -119,7 +122,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirEnumCompanionInEnumConstructorCallChecker, FirEnumCompanionInEnumConstructorCallChecker,
FirBadInheritedJavaSignaturesChecker, FirBadInheritedJavaSignaturesChecker,
FirSealedInterfaceAllowedChecker, FirSealedInterfaceAllowedChecker,
FirMixedFunctionalTypesInSupertypesChecker, FirMixedFunctionalTypesInSupertypesChecker.Regular,
FirMixedFunctionalTypesInSupertypesChecker.ForExpectClass,
) )
override val regularClassCheckers: Set<FirRegularClassChecker> override val regularClassCheckers: Set<FirRegularClassChecker>
@@ -135,13 +139,16 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirManyCompanionObjectsChecker, FirManyCompanionObjectsChecker,
FirMethodOfAnyImplementedInInterfaceChecker, FirMethodOfAnyImplementedInInterfaceChecker,
FirDataClassPrimaryConstructorChecker, FirDataClassPrimaryConstructorChecker,
FirFunInterfaceDeclarationChecker, FirFunInterfaceDeclarationChecker.Regular,
FirFunInterfaceDeclarationChecker.ForExpectClass,
FirNestedClassChecker, FirNestedClassChecker,
FirValueClassDeclarationChecker, FirValueClassDeclarationChecker.Regular,
FirValueClassDeclarationChecker.ForExpectClass,
FirOuterClassArgumentsRequiredChecker, FirOuterClassArgumentsRequiredChecker,
FirPropertyInitializationChecker, FirPropertyInitializationChecker,
FirDelegateFieldTypeMismatchChecker, FirDelegateFieldTypeMismatchChecker,
FirMultipleDefaultsInheritedFromSupertypesChecker, FirMultipleDefaultsInheritedFromSupertypesChecker.Regular,
FirMultipleDefaultsInheritedFromSupertypesChecker.ForExpectClass,
FirFiniteBoundRestrictionChecker, FirFiniteBoundRestrictionChecker,
FirNonExpansiveInheritanceRestrictionChecker, FirNonExpansiveInheritanceRestrictionChecker,
) )
@@ -176,7 +183,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val typeParameterCheckers: Set<FirTypeParameterChecker> override val typeParameterCheckers: Set<FirTypeParameterChecker>
get() = setOf( get() = setOf(
FirTypeParameterBoundsChecker, FirTypeParameterBoundsChecker.Regular,
FirTypeParameterBoundsChecker.ForExpectClass,
FirTypeParameterVarianceChecker, FirTypeParameterVarianceChecker,
FirReifiedTypeParameterChecker, FirReifiedTypeParameterChecker,
FirTypeParameterSyntaxChecker, FirTypeParameterSyntaxChecker,
@@ -18,18 +18,28 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CAN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.isFun
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.scopes.getFunctions import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.scopes.getProperties import org.jetbrains.kotlin.fir.scopes.getProperties
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
// TODO: extract common checker for expect interfaces
object FirFunInterfaceDeclarationChecker : FirRegularClassChecker(MppCheckerKind.Platform) { sealed class FirFunInterfaceDeclarationChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) {
object Regular : FirFunInterfaceDeclarationChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirFunInterfaceDeclarationChecker(MppCheckerKind.Common) {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isInterface || !declaration.isFun) return if (!declaration.isInterface || !declaration.isFun) return
@@ -40,8 +40,20 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeCheckerState import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
// TODO: extract common checker for expect interfaces sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirImplementationMismatchChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirImplementationMismatchChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirImplementationMismatchChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val source = declaration.source ?: return val source = declaration.source ?: return
@@ -13,11 +13,25 @@ import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.types.functionTypeKind import org.jetbrains.kotlin.fir.types.functionTypeKind
// TODO: extract common checker for expect interfaces sealed class FirMixedFunctionalTypesInSupertypesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirMixedFunctionalTypesInSupertypesChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirMixedFunctionalTypesInSupertypesChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirMixedFunctionalTypesInSupertypesChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val superKinds = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session) val superKinds = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session)
.mapNotNullTo(mutableSetOf()) { it.functionTypeKind(context.session)?.nonReflectKind() } .mapNotNullTo(mutableSetOf()) { it.functionTypeKind(context.session)?.nonReflectKind() }
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.isSubstitutionOverride import org.jetbrains.kotlin.fir.isSubstitutionOverride
import org.jetbrains.kotlin.fir.scopes.processAllFunctions import org.jetbrains.kotlin.fir.scopes.processAllFunctions
@@ -24,8 +25,21 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
// TODO: extract common checker for expect interfaces sealed class FirMultipleDefaultsInheritedFromSupertypesChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) {
object FirMultipleDefaultsInheritedFromSupertypesChecker : FirRegularClassChecker(MppCheckerKind.Platform) { object Regular : FirMultipleDefaultsInheritedFromSupertypesChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirMultipleDefaultsInheritedFromSupertypesChecker(MppCheckerKind.Common) {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.unsubstitutedScope(context).processAllFunctions { declaration.unsubstitutedScope(context).processAllFunctions {
val originalIfSubstitutionOverride = it.unwrapSubstitutionOverrides() val originalIfSubstitutionOverride = it.unwrapSubstitutionOverrides()
@@ -41,8 +41,20 @@ import org.jetbrains.kotlin.util.ImplementationStatus
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
// TODO: extract common checker for expect interfaces sealed class FirNotImplementedOverrideChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platform) { object Regular : FirNotImplementedOverrideChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirNotImplementedOverrideChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val source = declaration.source ?: return val source = declaration.source ?: return
@@ -15,11 +15,25 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.scopes.processAllCallables import org.jetbrains.kotlin.fir.scopes.processAllCallables
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
// TODO: extract common checker for expect interfaces sealed class FirNotImplementedOverrideSimpleEnumEntryChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
object FirNotImplementedOverrideSimpleEnumEntryChecker : FirClassChecker(MppCheckerKind.Common) { object Regular : FirNotImplementedOverrideSimpleEnumEntryChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirNotImplementedOverrideSimpleEnumEntryChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isEnumClass) return if (!declaration.isEnumClass) return
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.overridesBackwardCompatibilityHelper import org.jetbrains.kotlin.fir.analysis.overridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isFinal import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.originalOrSelf import org.jetbrains.kotlin.fir.originalOrSelf
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
@@ -107,8 +104,21 @@ abstract class FirAbstractOverrideChecker(mppKind: MppCheckerKind) : FirClassChe
} }
} }
// TODO: extract common checker for expect interfaces sealed class FirOverrideChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) {
object FirOverrideChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) { object Regular : FirOverrideChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
object ForExpectClass : FirOverrideChecker(MppCheckerKind.Common) {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val typeCheckerState = context.session.typeContext.newTypeCheckerState( val typeCheckerState = context.session.typeContext.newTypeCheckerState(
errorTypesEqualToAnything = false, errorTypesEqualToAnything = false,
@@ -13,14 +13,29 @@ import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isOverride import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext
// TODO: extract common checker for expect interfaces sealed class FirTypeParameterBoundsChecker(mppKind: MppCheckerKind) : FirTypeParameterChecker(mppKind) {
object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Platform) { object Regular : FirTypeParameterBoundsChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return
if ((containingDeclaration as? FirMemberDeclaration)?.isExpect == true) return
check(declaration, containingDeclaration, context, reporter)
}
}
object ForExpectClass : FirTypeParameterBoundsChecker(MppCheckerKind.Common) {
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return
if ((containingDeclaration as? FirMemberDeclaration)?.isExpect != true) return
check(declaration, containingDeclaration, context, reporter)
}
}
private val classKinds = setOf( private val classKinds = setOf(
ClassKind.CLASS, ClassKind.CLASS,
@@ -28,8 +43,12 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Pl
ClassKind.OBJECT ClassKind.OBJECT
) )
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) { protected fun check(
val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return declaration: FirTypeParameter,
containingDeclaration: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
if (containingDeclaration is FirConstructor) return if (containingDeclaration is FirConstructor) return
checkFinalUpperBounds(declaration, containingDeclaration, context, reporter) checkFinalUpperBounds(declaration, containingDeclaration, context, reporter)
@@ -33,13 +33,27 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
// TODO: extract common checker for expect interfaces sealed class FirValueClassDeclarationChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) {
object FirValueClassDeclarationChecker : FirRegularClassChecker(MppCheckerKind.Platform) { object Regular : FirValueClassDeclarationChecker(MppCheckerKind.Platform) {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration.isExpect) return
super.check(declaration, context, reporter)
}
}
private val boxAndUnboxNames = setOf("box", "unbox") object ForExpectClass : FirValueClassDeclarationChecker(MppCheckerKind.Common) {
private val equalsAndHashCodeNames = setOf("equals", "hashCode") override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
private val javaLangFqName = FqName("java.lang") if (!declaration.isExpect) return
private val cloneableFqName = FqName("Cloneable") super.check(declaration, context, reporter)
}
}
companion object {
private val boxAndUnboxNames = setOf("box", "unbox")
private val equalsAndHashCodeNames = setOf("equals", "hashCode")
private val javaLangFqName = FqName("java.lang")
private val cloneableFqName = FqName("Cloneable")
}
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.symbol.isInlineOrValueClass()) { if (!declaration.symbol.isInlineOrValueClass()) {