[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<*>>>()
|
||||
|
||||
Reference in New Issue
Block a user