[FIR] Cleanup: extract reportClassScopesIncompatibility into its own function
Review: https://jetbrains.team/p/kt/reviews/13094/timeline
This commit is contained in:
+63
-51
@@ -155,57 +155,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
when {
|
||||
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
|
||||
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
|
||||
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
|
||||
}
|
||||
|
||||
// Do not report "expected members have no actual ones" for those expected members, for which there's a clear
|
||||
// (albeit maybe incompatible) single actual suspect, declared in the actual class.
|
||||
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
|
||||
// later when this checker is called for them
|
||||
fun hasSingleActualSuspect(
|
||||
expectedWithIncompatibility: Pair<FirBasedSymbol<*>, Map<out ExpectActualCheckingCompatibility.Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>,
|
||||
): Boolean {
|
||||
val (expectedMember, incompatibility) = expectedWithIncompatibility
|
||||
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
|
||||
@OptIn(SymbolInternals::class)
|
||||
return actualMember != null &&
|
||||
actualMember.fir.expectForActual?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
||||
}
|
||||
|
||||
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
|
||||
|
||||
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
|
||||
val (defaultArgsIncompatibleMembers, otherIncompatibleMembers) =
|
||||
nonTrivialIncompatibleMembers.partition { it.second.contains(ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride) }
|
||||
|
||||
if (defaultArgsIncompatibleMembers.isNotEmpty()) { // report a nicer diagnostic for DefaultArgumentsInExpectActualizedByFakeOverride
|
||||
val problematicExpectMembers = defaultArgsIncompatibleMembers
|
||||
.map {
|
||||
it.first as? FirNamedFunctionSymbol
|
||||
?: error("${ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride} can be reported only for ${FirNamedFunctionSymbol::class}")
|
||||
}
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
|
||||
expectedSingleCandidate,
|
||||
problematicExpectMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
if (otherIncompatibleMembers.isNotEmpty()) {
|
||||
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, otherIncompatibleMembers, context)
|
||||
}
|
||||
}
|
||||
if (checkingCompatibility.mismatchedMembers.isNotEmpty()) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS,
|
||||
symbol,
|
||||
checkingCompatibility.mismatchedMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
reportClassScopesIncompatibility(symbol, expectedSingleCandidate, declaration, checkingCompatibility, reporter, source, context)
|
||||
}
|
||||
|
||||
ExpectActualMatchingCompatibility.MatchedSuccessfully !in matchingCompatibilityToMembersMap &&
|
||||
@@ -242,6 +192,68 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportClassScopesIncompatibility(
|
||||
symbol: FirBasedSymbol<out FirDeclaration>,
|
||||
expectedSingleCandidate: FirBasedSymbol<*>?,
|
||||
declaration: FirMemberDeclaration,
|
||||
checkingCompatibility: ExpectActualCheckingCompatibility.ClassScopes<FirBasedSymbol<*>>,
|
||||
reporter: DiagnosticReporter,
|
||||
source: KtSourceElement?,
|
||||
context: CheckerContext,
|
||||
) {
|
||||
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
|
||||
"Incompatible.ClassScopes is only possible for a class or a typealias: $declaration"
|
||||
}
|
||||
|
||||
// Do not report "expected members have no actual ones" for those expected members, for which there's a clear
|
||||
// (albeit maybe incompatible) single actual suspect, declared in the actual class.
|
||||
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
|
||||
// later when this checker is called for them
|
||||
fun hasSingleActualSuspect(
|
||||
expectedWithIncompatibility: Pair<FirBasedSymbol<*>, Map<out ExpectActualCheckingCompatibility.Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>,
|
||||
): Boolean {
|
||||
val (expectedMember, incompatibility) = expectedWithIncompatibility
|
||||
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
|
||||
@OptIn(SymbolInternals::class)
|
||||
return actualMember != null &&
|
||||
actualMember.fir.expectForActual?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
||||
}
|
||||
|
||||
val nonTrivialIncompatibleMembers = checkingCompatibility.incompatibleMembers.filterNot(::hasSingleActualSuspect)
|
||||
|
||||
if (nonTrivialIncompatibleMembers.isNotEmpty()) {
|
||||
val (defaultArgsIncompatibleMembers, otherIncompatibleMembers) =
|
||||
nonTrivialIncompatibleMembers.partition { it.second.contains(ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride) }
|
||||
|
||||
if (defaultArgsIncompatibleMembers.isNotEmpty()) { // report a nicer diagnostic for DefaultArgumentsInExpectActualizedByFakeOverride
|
||||
val problematicExpectMembers = defaultArgsIncompatibleMembers
|
||||
.map {
|
||||
it.first as? FirNamedFunctionSymbol
|
||||
?: error("${ExpectActualCheckingCompatibility.DefaultArgumentsInExpectActualizedByFakeOverride} can be reported only for ${FirNamedFunctionSymbol::class}")
|
||||
}
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.DEFAULT_ARGUMENTS_IN_EXPECT_ACTUALIZED_BY_FAKE_OVERRIDE,
|
||||
expectedSingleCandidate,
|
||||
problematicExpectMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
if (otherIncompatibleMembers.isNotEmpty()) {
|
||||
reporter.reportOn(source, FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, symbol, otherIncompatibleMembers, context)
|
||||
}
|
||||
}
|
||||
if (checkingCompatibility.mismatchedMembers.isNotEmpty()) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS,
|
||||
symbol,
|
||||
checkingCompatibility.mismatchedMembers,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCheckingCompatibility(
|
||||
actualSymbol: FirBasedSymbol<*>,
|
||||
expectSymbol: FirBasedSymbol<*>,
|
||||
|
||||
Reference in New Issue
Block a user