[FE 1.0] Deprecate declaration of expect and actual in the same module

^KT-40904 Fixed
^KT-55177 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-01-13 12:57:59 +02:00
committed by Space Team
parent 71a80c5e36
commit b09561c3c3
18 changed files with 120 additions and 9 deletions
@@ -805,6 +805,8 @@ public interface Errors {
DiagnosticFactory2.create(ERROR, ACTUAL_DECLARATION_NAME);
DiagnosticFactory0<KtNamedDeclaration> ACTUAL_MISSING = DiagnosticFactory0.create(ERROR, ACTUAL_DECLARATION_NAME);
DiagnosticFactory0<KtNamedDeclaration> EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE = DiagnosticFactory0.create(WARNING, DECLARATION_NAME);
DiagnosticFactory0<PsiElement> OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR);
@@ -339,6 +339,7 @@ public class DefaultErrorMessages {
MAP.put(NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, "Actual class ''{0}'' has no corresponding members for expected class members:{1}",
NAME, adaptGenerics2(IncompatibleExpectedActualClassScopesRenderer.TEXT));
MAP.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'");
MAP.put(EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE, "Expect and corresponding actual are declared in the same module, which will be prohibited in Kotlin 2.0. See https://youtrack.jetbrains.com/issue/KT-55177");
MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class");
MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry");
@@ -181,27 +181,46 @@ class ExpectedActualDeclarationChecker(
}
// Here we have exactly one compatible actual and/or some weakly incompatible. In either case, we don't report anything on expect...
val actualMembers = actuals.asSequence()
.filter { it.key.isCompatibleOrWeakCompatible() }.flatMap { it.value.asSequence() }
val actualMembers = actuals.filter { it.key.isCompatibleOrWeakCompatible() }.flatMap { it.value }
// ...except diagnostics regarding missing actual keyword, because in that case we won't start looking for the actual at all
if (checkActualModifier) {
actualMembers.forEach { reportMissingActualModifier(it, reportOn = null, trace) }
}
reportExpectAndActualInTheSameModule(reportOn, actualMembers, trace)
expectActualTracker.reportExpectActual(expected = expectDescriptor, actualMembers = actualMembers)
}
private fun reportMissingActualModifier(actual: MemberDescriptor, reportOn: KtNamedDeclaration?, trace: BindingTrace) {
if (actual.isActual) return
@Suppress("NAME_SHADOWING")
val reportOn = reportOn ?: (actual.source as? KotlinSourceElement)?.psi as? KtNamedDeclaration ?: return
val reportOn = reportOn ?: actual.declarationSource ?: return
if (requireActualModifier(actual)) {
trace.report(Errors.ACTUAL_MISSING.on(reportOn))
}
}
private val MemberDescriptor.declarationSource: KtNamedDeclaration?
get() = (this.source as? KotlinSourceElement)?.psi as? KtNamedDeclaration
private fun reportExpectAndActualInTheSameModule(
expectSource: KtNamedDeclaration,
actualMembers: List<MemberDescriptor>,
trace: BindingTrace
) {
if (expectSource.containingKtFile.isCommonSource == true) return
val actualMembersWithModifier = actualMembers.filter { it.isActual }
if (actualMembersWithModifier.isEmpty()) return
trace.report(Errors.EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE.on(expectSource))
for (actual in actualMembersWithModifier) {
val actualSource = actual.declarationSource ?: continue
trace.report(Errors.EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE.on(actualSource))
}
}
private fun MemberDescriptor.hasNoActualWithDiagnostic(
compatibility: Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>
): Boolean {
@@ -211,7 +230,7 @@ class ExpectedActualDeclarationChecker(
}
}
private fun ExpectActualTracker.reportExpectActual(expected: MemberDescriptor, actualMembers: Sequence<MemberDescriptor>) {
private fun ExpectActualTracker.reportExpectActual(expected: MemberDescriptor, actualMembers: List<MemberDescriptor>) {
if (this is ExpectActualTracker.DoNothing) return
val expectedFile = sourceFile(expected) ?: return