[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:
committed by
Nikolay Lunyak
parent
f5d8113de3
commit
990da9fa1a
+10
-5
@@ -12,7 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration.FirJsEx
|
||||
object JsDeclarationCheckers : DeclarationCheckers() {
|
||||
override val functionCheckers: Set<FirFunctionChecker>
|
||||
get() = setOf(
|
||||
FirJsInheritanceFunctionChecker,
|
||||
FirJsInheritanceFunctionChecker.Regular,
|
||||
FirJsInheritanceFunctionChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
@@ -30,11 +31,15 @@ object JsDeclarationCheckers : DeclarationCheckers() {
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirJsMultipleInheritanceChecker,
|
||||
FirJsMultipleInheritanceChecker.Regular,
|
||||
FirJsMultipleInheritanceChecker.ForExpectClass,
|
||||
FirJsDynamicDeclarationChecker,
|
||||
FirJsInheritanceClassChecker,
|
||||
FirJsExternalInheritorOnlyChecker,
|
||||
FirJsNameClashClassMembersChecker
|
||||
FirJsInheritanceClassChecker.Regular,
|
||||
FirJsInheritanceClassChecker.ForExpectClass,
|
||||
FirJsExternalInheritorOnlyChecker.Regular,
|
||||
FirJsExternalInheritorOnlyChecker.ForExpectClass,
|
||||
FirJsNameClashClassMembersChecker.Regular,
|
||||
FirJsNameClashClassMembersChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
|
||||
+16
-2
@@ -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.declarations.FirClass
|
||||
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.symbols.impl.FirRegularClassSymbol
|
||||
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.utils.addToStdlib.popLast
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirJsExternalInheritorOnlyChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirJsExternalInheritorOnlyChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
val todo = superConeTypes.toMutableList()
|
||||
val done = hashSetOf<FirRegularClassSymbol>()
|
||||
|
||||
+16
-2
@@ -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.isOverridingExternalWithOptionalParams
|
||||
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.scopes.collectAllFunctions
|
||||
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.typeContext
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirJsInheritanceClassChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirJsInheritanceClassChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
if (!declaration.symbol.isEffectivelyExternal(context)) {
|
||||
val fakeOverriddenMethod = declaration.findFakeMethodOverridingExternalWithOptionalParams(context)
|
||||
|
||||
+17
-2
@@ -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.js.checkers.isEffectivelyExternal
|
||||
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.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) {
|
||||
if (declaration.isNotEffectivelyExternalFunctionButOverridesExternal(context)) {
|
||||
reporter.reportOn(declaration.source, FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, context)
|
||||
|
||||
+16
-2
@@ -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.diagnostics.js.FirJsErrors
|
||||
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.scopes.getFunctions
|
||||
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.util.OperatorNameConventions
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirJsMultipleInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirJsMultipleInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
declaration.checkFunctionIfSubtypeOf(
|
||||
functionToCheck = OperatorNameConventions.GET,
|
||||
|
||||
+16
-2
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
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.scopes.*
|
||||
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.addToStdlib.popLast
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirJsNameClashClassMembersChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirJsNameClashClassMembersChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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 {
|
||||
val jsStableNames = mutableSetOf<FirJsStableName>()
|
||||
val overrideIntersections = hashMapOf<FirCallableSymbol<*>, HashSet<FirCallableSymbol<*>>>()
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirStrictfpApplicabilityChecker,
|
||||
FirOverrideJavaNullabilityWarningChecker,
|
||||
FirOverrideJavaNullabilityWarningChecker.Regular,
|
||||
FirOverrideJavaNullabilityWarningChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val regularClassCheckers: Set<FirRegularClassChecker>
|
||||
|
||||
+16
-2
@@ -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.diagnostics.jvm.FirJvmErrors
|
||||
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.scopes.*
|
||||
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.utils.addToStdlib.runIf
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirOverrideJavaNullabilityWarningChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirOverrideJavaNullabilityWarningChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) {
|
||||
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) {
|
||||
val substitutor = EnhancedForWarningConeSubstitutor(context.session.typeContext)
|
||||
val scope = declaration.unsubstitutedScope(context)
|
||||
|
||||
+26
-7
@@ -14,14 +14,33 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
|
||||
object FirNativeObjCNameCallableChecker : FirCallableDeclarationChecker(MppCheckerKind.Common) {
|
||||
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirSimpleFunction && declaration !is FirProperty) return
|
||||
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass
|
||||
if (containingClass != null) {
|
||||
val firTypeScope = containingClass.unsubstitutedScope(context)
|
||||
FirNativeObjCNameUtilities.checkCallableMember(firTypeScope, declaration.symbol, declaration, context, reporter)
|
||||
sealed class FirNativeObjCNameCallableChecker(mppKind: MppCheckerKind) : FirCallableDeclarationChecker(mppKind) {
|
||||
object Regular : FirNativeObjCNameCallableChecker(MppCheckerKind.Platform) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -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.native.checkers.FirNativeObjCNameUtilities.checkCallableMember
|
||||
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.scopes.processAllFunctions
|
||||
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) {
|
||||
// We just need to check intersection overrides, all other declarations are checked by FirNativeObjCNameChecker
|
||||
|
||||
+9
-2
@@ -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.unsubstitutedScope
|
||||
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.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -35,7 +34,15 @@ object FirNativeObjCRefinementChecker : FirCallableDeclarationChecker(MppChecker
|
||||
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass
|
||||
if (containingClass != null) {
|
||||
val firTypeScope = containingClass.unsubstitutedScope(context)
|
||||
check(firTypeScope, declaration.symbol, declaration, context, reporter, objCAnnotations, swiftAnnotations)
|
||||
FirNativeObjCRefinementOverridesChecker.check(
|
||||
firTypeScope,
|
||||
declaration.symbol,
|
||||
declaration,
|
||||
context,
|
||||
reporter,
|
||||
objCAnnotations,
|
||||
swiftAnnotations
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+82
-66
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||
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.isIntersectionOverride
|
||||
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.symbols.impl.FirCallableSymbol
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirNativeObjCRefinementOverridesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
// We just need to check intersection overrides, all other declarations are checked by FirNativeObjCRefinementChecker
|
||||
@@ -45,80 +58,83 @@ object FirNativeObjCRefinementOverridesChecker : FirClassChecker(MppCheckerKind.
|
||||
}
|
||||
}
|
||||
|
||||
fun check(
|
||||
baseScope: FirTypeScope,
|
||||
memberSymbol: FirCallableSymbol<*>,
|
||||
declarationToReport: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
objCAnnotations: List<FirAnnotation>,
|
||||
swiftAnnotations: List<FirAnnotation>
|
||||
) {
|
||||
val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol)
|
||||
if (overriddenMemberSymbols.isEmpty()) return
|
||||
var isHiddenFromObjC = objCAnnotations.isNotEmpty()
|
||||
var isRefinedInSwift = swiftAnnotations.isNotEmpty()
|
||||
val supersNotHiddenFromObjC = mutableListOf<FirCallableSymbol<*>>()
|
||||
val supersNotRefinedInSwift = mutableListOf<FirCallableSymbol<*>>()
|
||||
for ((symbol, scope) in overriddenMemberSymbols) {
|
||||
val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope)
|
||||
if (superIsHiddenFromObjC) isHiddenFromObjC = true else supersNotHiddenFromObjC.add(symbol)
|
||||
if (superIsRefinedInSwift) isRefinedInSwift = true else supersNotRefinedInSwift.add(symbol)
|
||||
companion object {
|
||||
fun check(
|
||||
baseScope: FirTypeScope,
|
||||
memberSymbol: FirCallableSymbol<*>,
|
||||
declarationToReport: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
objCAnnotations: List<FirAnnotation>,
|
||||
swiftAnnotations: List<FirAnnotation>
|
||||
) {
|
||||
val overriddenMemberSymbols = baseScope.getDirectOverriddenMembersWithBaseScope(memberSymbol)
|
||||
if (overriddenMemberSymbols.isEmpty()) return
|
||||
var isHiddenFromObjC = objCAnnotations.isNotEmpty()
|
||||
var isRefinedInSwift = swiftAnnotations.isNotEmpty()
|
||||
val supersNotHiddenFromObjC = mutableListOf<FirCallableSymbol<*>>()
|
||||
val supersNotRefinedInSwift = mutableListOf<FirCallableSymbol<*>>()
|
||||
for ((symbol, scope) in overriddenMemberSymbols) {
|
||||
val (superIsHiddenFromObjC, superIsRefinedInSwift) = symbol.inheritsRefinedAnnotations(context.session, scope)
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair<Boolean, Boolean> {
|
||||
var hasObjC = false
|
||||
var hasSwift = false
|
||||
for (annotation in resolvedAnnotationsWithClassIds) {
|
||||
val metaAnnotations = annotation.toAnnotationClassLikeSymbol(session)?.resolvedAnnotationsWithClassIds.orEmpty()
|
||||
for (metaAnnotation in metaAnnotations) {
|
||||
when (metaAnnotation.toAnnotationClassId(session)) {
|
||||
hidesFromObjCClassId -> {
|
||||
hasObjC = true
|
||||
break
|
||||
}
|
||||
|
||||
private fun FirCallableSymbol<*>.hasRefinedAnnotations(session: FirSession): Pair<Boolean, Boolean> {
|
||||
var hasObjC = false
|
||||
var hasSwift = false
|
||||
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
|
||||
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(
|
||||
declaration: FirDeclaration,
|
||||
annotations: List<FirAnnotation>,
|
||||
notRefinedSupers: List<FirCallableSymbol<*>>,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) }
|
||||
if (annotations.isEmpty()) {
|
||||
reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
|
||||
} else {
|
||||
for (annotation in annotations) {
|
||||
reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
|
||||
private fun DiagnosticReporter.reportIncompatibleOverride(
|
||||
declaration: FirDeclaration,
|
||||
annotations: List<FirAnnotation>,
|
||||
notRefinedSupers: List<FirCallableSymbol<*>>,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val containingDeclarations = notRefinedSupers.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) }
|
||||
if (annotations.isEmpty()) {
|
||||
reportOn(declaration.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
|
||||
} else {
|
||||
for (annotation in annotations) {
|
||||
reportOn(annotation.source, INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE, declaration.symbol, containingDeclarations, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+28
-11
@@ -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.containingClassLookupTag
|
||||
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.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
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.resolve.annotations.KOTLIN_THROWS_ANNOTATION_FQ_NAME
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirNativeThrowsChecker : FirBasicDeclarationChecker(MppCheckerKind.Platform) {
|
||||
private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME)
|
||||
sealed class FirNativeThrowsChecker(mppKind: MppCheckerKind) : FirBasicDeclarationChecker(mppKind) {
|
||||
object Regular : FirNativeThrowsChecker(MppCheckerKind.Platform) {
|
||||
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(
|
||||
ClassId.topLevel(StandardNames.FqNames.throwable),
|
||||
ClassId.topLevel(FqName("kotlin.Exception")),
|
||||
ClassId.topLevel(FqName("kotlin.RuntimeException")),
|
||||
ClassId.topLevel(FqName("kotlin.IllegalStateException")),
|
||||
ClassId.topLevel(cancellationExceptionFqName)
|
||||
)
|
||||
companion object {
|
||||
private val throwsClassId = ClassId.topLevel(KOTLIN_THROWS_ANNOTATION_FQ_NAME)
|
||||
|
||||
private val cancellationExceptionFqName = FqName("kotlin.coroutines.cancellation.CancellationException")
|
||||
|
||||
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) {
|
||||
val throwsAnnotation = declaration.getAnnotationByClassId(throwsClassId, context.session) as? FirAnnotationCall
|
||||
|
||||
+8
-4
@@ -10,7 +10,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
|
||||
object NativeDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
get() = setOf(
|
||||
FirNativeThrowsChecker,
|
||||
FirNativeThrowsChecker.Regular,
|
||||
FirNativeThrowsChecker.ForExpectClass,
|
||||
FirNativeSharedImmutableChecker,
|
||||
FirNativeThreadLocalChecker,
|
||||
FirNativeIdentifierChecker,
|
||||
@@ -20,13 +21,16 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
|
||||
override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker>
|
||||
get() = setOf(
|
||||
FirNativeObjCRefinementChecker,
|
||||
FirNativeObjCNameCallableChecker,
|
||||
FirNativeObjCNameCallableChecker.Regular,
|
||||
FirNativeObjCNameCallableChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirNativeObjCRefinementOverridesChecker,
|
||||
FirNativeObjCNameOverridesChecker,
|
||||
FirNativeObjCRefinementOverridesChecker.Regular,
|
||||
FirNativeObjCRefinementOverridesChecker.ForExpectClass,
|
||||
FirNativeObjCNameOverridesChecker.Regular,
|
||||
FirNativeObjCNameOverridesChecker.ForExpectClass,
|
||||
FirNativeObjCOutletChecker,
|
||||
FirNativeObjCActionChecker,
|
||||
FirNativeObjCOverrideInitChecker,
|
||||
|
||||
+6
-3
@@ -5,14 +5,17 @@
|
||||
|
||||
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.web.common.checkers.declaration.FirJsExportAnnotationChecker
|
||||
|
||||
object WasmBaseDeclarationCheckers : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirWasmExternalInheritanceChecker,
|
||||
FirWasmExternalInheritanceChecker.Regular,
|
||||
FirWasmExternalInheritanceChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
@@ -39,4 +42,4 @@ object WasmWasiDeclarationCheckers : DeclarationCheckers() {
|
||||
get() = setOf(
|
||||
FirWasmWasiExternalDeclarationChecker,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+16
-2
@@ -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.declarations.FirClass
|
||||
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.name.StandardClassIds
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirWasmExternalInheritanceChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirWasmExternalInheritanceChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
val session = context.session
|
||||
val isCurrentClassExternal = declaration.symbol.isEffectivelyExternal(session)
|
||||
|
||||
@@ -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`
|
||||
- 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
|
||||
|
||||
#### 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
|
||||
|
||||
+18
-10
@@ -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.declaration.*
|
||||
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.FirMissingDependencySupertypeChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirSuspendAnonymousFunctionChecker
|
||||
@@ -103,15 +102,19 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirOverrideChecker,
|
||||
FirNotImplementedOverrideChecker,
|
||||
FirNotImplementedOverrideSimpleEnumEntryChecker,
|
||||
FirOverrideChecker.Regular,
|
||||
FirOverrideChecker.ForExpectClass,
|
||||
FirNotImplementedOverrideChecker.Regular,
|
||||
FirNotImplementedOverrideChecker.ForExpectClass,
|
||||
FirNotImplementedOverrideSimpleEnumEntryChecker.Regular,
|
||||
FirNotImplementedOverrideSimpleEnumEntryChecker.ForExpectClass,
|
||||
FirThrowableSubclassChecker,
|
||||
FirOpenMemberChecker,
|
||||
FirClassVarianceChecker,
|
||||
FirSealedSupertypeChecker,
|
||||
FirMemberPropertiesChecker,
|
||||
FirImplementationMismatchChecker,
|
||||
FirImplementationMismatchChecker.Regular,
|
||||
FirImplementationMismatchChecker.ForExpectClass,
|
||||
FirTypeParametersInObjectChecker,
|
||||
FirSupertypesChecker,
|
||||
FirPrimaryConstructorSuperTypeChecker,
|
||||
@@ -119,7 +122,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirEnumCompanionInEnumConstructorCallChecker,
|
||||
FirBadInheritedJavaSignaturesChecker,
|
||||
FirSealedInterfaceAllowedChecker,
|
||||
FirMixedFunctionalTypesInSupertypesChecker,
|
||||
FirMixedFunctionalTypesInSupertypesChecker.Regular,
|
||||
FirMixedFunctionalTypesInSupertypesChecker.ForExpectClass,
|
||||
)
|
||||
|
||||
override val regularClassCheckers: Set<FirRegularClassChecker>
|
||||
@@ -135,13 +139,16 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirManyCompanionObjectsChecker,
|
||||
FirMethodOfAnyImplementedInInterfaceChecker,
|
||||
FirDataClassPrimaryConstructorChecker,
|
||||
FirFunInterfaceDeclarationChecker,
|
||||
FirFunInterfaceDeclarationChecker.Regular,
|
||||
FirFunInterfaceDeclarationChecker.ForExpectClass,
|
||||
FirNestedClassChecker,
|
||||
FirValueClassDeclarationChecker,
|
||||
FirValueClassDeclarationChecker.Regular,
|
||||
FirValueClassDeclarationChecker.ForExpectClass,
|
||||
FirOuterClassArgumentsRequiredChecker,
|
||||
FirPropertyInitializationChecker,
|
||||
FirDelegateFieldTypeMismatchChecker,
|
||||
FirMultipleDefaultsInheritedFromSupertypesChecker,
|
||||
FirMultipleDefaultsInheritedFromSupertypesChecker.Regular,
|
||||
FirMultipleDefaultsInheritedFromSupertypesChecker.ForExpectClass,
|
||||
FirFiniteBoundRestrictionChecker,
|
||||
FirNonExpansiveInheritanceRestrictionChecker,
|
||||
)
|
||||
@@ -176,7 +183,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
|
||||
override val typeParameterCheckers: Set<FirTypeParameterChecker>
|
||||
get() = setOf(
|
||||
FirTypeParameterBoundsChecker,
|
||||
FirTypeParameterBoundsChecker.Regular,
|
||||
FirTypeParameterBoundsChecker.ForExpectClass,
|
||||
FirTypeParameterVarianceChecker,
|
||||
FirReifiedTypeParameterChecker,
|
||||
FirTypeParameterSyntaxChecker,
|
||||
|
||||
+16
-6
@@ -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_WRONG_COUNT_OF_ABSTRACT_MEMBERS
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
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.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.scopes.getFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.getProperties
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
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) {
|
||||
if (!declaration.isInterface || !declaration.isFun) return
|
||||
|
||||
+14
-2
@@ -40,8 +40,20 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirImplementationMismatchChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirImplementationMismatchChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
val source = declaration.source ?: return
|
||||
|
||||
+16
-2
@@ -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.diagnostics.FirErrors
|
||||
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.types.functionTypeKind
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirMixedFunctionalTypesInSupertypesChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirMixedFunctionalTypesInSupertypesChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
val superKinds = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session)
|
||||
.mapNotNullTo(mutableSetOf()) { it.functionTypeKind(context.session)?.nonReflectKind() }
|
||||
|
||||
+16
-2
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
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.isSubstitutionOverride
|
||||
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.name.Name
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirMultipleDefaultsInheritedFromSupertypesChecker : FirRegularClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirMultipleDefaultsInheritedFromSupertypesChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) {
|
||||
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) {
|
||||
declaration.unsubstitutedScope(context).processAllFunctions {
|
||||
val originalIfSubstitutionOverride = it.unwrapSubstitutionOverrides()
|
||||
|
||||
+14
-2
@@ -41,8 +41,20 @@ import org.jetbrains.kotlin.util.ImplementationStatus
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirNotImplementedOverrideChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
val source = declaration.source ?: return
|
||||
|
||||
+16
-2
@@ -15,11 +15,25 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
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.symbols.impl.FirCallableSymbol
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirNotImplementedOverrideSimpleEnumEntryChecker : FirClassChecker(MppCheckerKind.Common) {
|
||||
sealed class FirNotImplementedOverrideSimpleEnumEntryChecker(mppKind: MppCheckerKind) : FirClassChecker(mppKind) {
|
||||
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) {
|
||||
if (!declaration.isEnumClass) return
|
||||
|
||||
|
||||
+16
-6
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.overridesBackwardCompatibilityHelper
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
|
||||
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.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.originalOrSelf
|
||||
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
|
||||
object FirOverrideChecker : FirAbstractOverrideChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirOverrideChecker(mppKind: MppCheckerKind) : FirAbstractOverrideChecker(mppKind) {
|
||||
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) {
|
||||
val typeCheckerState = context.session.typeContext.newTypeCheckerState(
|
||||
errorTypesEqualToAnything = false,
|
||||
|
||||
+23
-4
@@ -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.diagnostics.FirErrors
|
||||
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.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirTypeParameterBoundsChecker(mppKind: MppCheckerKind) : FirTypeParameterChecker(mppKind) {
|
||||
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(
|
||||
ClassKind.CLASS,
|
||||
@@ -28,8 +43,12 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker(MppCheckerKind.Pl
|
||||
ClassKind.OBJECT
|
||||
)
|
||||
|
||||
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val containingDeclaration = context.containingDeclarations.lastOrNull() ?: return
|
||||
protected fun check(
|
||||
declaration: FirTypeParameter,
|
||||
containingDeclaration: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
) {
|
||||
if (containingDeclaration is FirConstructor) return
|
||||
|
||||
checkFinalUpperBounds(declaration, containingDeclaration, context, reporter)
|
||||
|
||||
+20
-6
@@ -33,13 +33,27 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirValueClassDeclarationChecker : FirRegularClassChecker(MppCheckerKind.Platform) {
|
||||
sealed class FirValueClassDeclarationChecker(mppKind: MppCheckerKind) : FirRegularClassChecker(mppKind) {
|
||||
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")
|
||||
private val equalsAndHashCodeNames = setOf("equals", "hashCode")
|
||||
private val javaLangFqName = FqName("java.lang")
|
||||
private val cloneableFqName = FqName("Cloneable")
|
||||
object ForExpectClass : FirValueClassDeclarationChecker(MppCheckerKind.Common) {
|
||||
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isExpect) return
|
||||
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) {
|
||||
if (!declaration.symbol.isInlineOrValueClass()) {
|
||||
|
||||
Reference in New Issue
Block a user