[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 {
|
when {
|
||||||
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
|
checkingCompatibility is ExpectActualCheckingCompatibility.ClassScopes -> {
|
||||||
require((symbol is FirRegularClassSymbol || symbol is FirTypeAliasSymbol) && expectedSingleCandidate is FirRegularClassSymbol) {
|
reportClassScopesIncompatibility(symbol, expectedSingleCandidate, declaration, checkingCompatibility, reporter, source, context)
|
||||||
"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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpectActualMatchingCompatibility.MatchedSuccessfully !in matchingCompatibilityToMembersMap &&
|
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(
|
private fun getCheckingCompatibility(
|
||||||
actualSymbol: FirBasedSymbol<*>,
|
actualSymbol: FirBasedSymbol<*>,
|
||||||
expectSymbol: FirBasedSymbol<*>,
|
expectSymbol: FirBasedSymbol<*>,
|
||||||
|
|||||||
Reference in New Issue
Block a user