[FE] Prohibit protected members in final expected or actual classes
^KT-28850 Fixed
This commit is contained in:
committed by
Space Team
parent
2f5b1dff16
commit
b368b78faa
+6
@@ -21232,6 +21232,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedInExpectActual.kt")
|
||||
public void testProtectedInExpectActual() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protectedInExpectActual.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
|
||||
+6
@@ -21232,6 +21232,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedInExpectActual.kt")
|
||||
public void testProtectedInExpectActual() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protectedInExpectActual.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
|
||||
+6
@@ -21232,6 +21232,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedInExpectActual.kt")
|
||||
public void testProtectedInExpectActual() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protectedInExpectActual.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
|
||||
+6
@@ -21238,6 +21238,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedInExpectActual.kt")
|
||||
public void testProtectedInExpectActual() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protectedInExpectActual.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
|
||||
+16
-4
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory2
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -85,7 +83,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
val modifier = secondModifier.token
|
||||
when {
|
||||
!checkTarget(modifierSource, modifier, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
|
||||
!checkParent(modifierSource, modifier, actualParents, context, reporter) -> reportedNodes += secondModifier
|
||||
!checkParent(modifierSource, modifier, actualParents, parent, context, reporter) -> reportedNodes += secondModifier
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,6 +234,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
modifierSource: KtSourceElement,
|
||||
modifierToken: KtModifierKeywordToken,
|
||||
actualParents: List<KotlinTarget>,
|
||||
parent: FirDeclaration?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
): Boolean {
|
||||
@@ -251,6 +250,15 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
return true
|
||||
}
|
||||
|
||||
if (modifierToken == KtTokens.PROTECTED_KEYWORD && isFinalExpectOrActualClass(parent)) {
|
||||
reporter.reportOn(
|
||||
modifierSource,
|
||||
FirErrors.WRONG_MODIFIER_CONTAINING_DECLARATION,
|
||||
modifierToken,
|
||||
"final expect or actual class",
|
||||
context,
|
||||
)
|
||||
}
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierToken] ?: return true
|
||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, context.session.languageVersionSettings) }) return true
|
||||
|
||||
@@ -268,4 +276,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
private fun List<KotlinTarget>.firstOrThis(): String {
|
||||
return firstOrNull()?.description ?: "this"
|
||||
}
|
||||
|
||||
private fun isFinalExpectOrActualClass(d: FirDeclaration?): Boolean {
|
||||
return d is FirClass && d.isFinal && (d.isExpect || d.isActual)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,15 @@ object ModifierCheckerCore {
|
||||
)
|
||||
return true
|
||||
}
|
||||
if (modifier == PROTECTED_KEYWORD && isFinalExpectOrActualClass(parentDescriptor)) {
|
||||
trace.report(
|
||||
Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(
|
||||
node.psi,
|
||||
modifier,
|
||||
"final expect or actual class"
|
||||
)
|
||||
)
|
||||
}
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
|
||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
||||
trace.report(
|
||||
@@ -237,4 +246,8 @@ object ModifierCheckerCore {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isFinalExpectOrActualClass(d: DeclarationDescriptor?): Boolean {
|
||||
return d is ClassDescriptor && d.isFinalOrEnum && (d.isExpect || d.isActual)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// LANGUAGE: +MultiPlatformProjects
|
||||
// !DIAGNOSTICS: -NO_ACTUAL_FOR_EXPECT, -ACTUAL_WITHOUT_EXPECT
|
||||
// FIR_IDENTICAL
|
||||
class SimpleClass {
|
||||
protected fun foo() = Unit
|
||||
}
|
||||
|
||||
expect class ExpClass {
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> fun foo()
|
||||
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> val bar: Int
|
||||
}
|
||||
|
||||
actual class ActClass {
|
||||
actual <!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> fun foo() = Unit
|
||||
|
||||
actual <!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> val bar: Int = 42
|
||||
}
|
||||
|
||||
expect open class ExpOpenClass {
|
||||
protected fun foo()
|
||||
}
|
||||
|
||||
actual open class ActOpenClass {
|
||||
actual protected fun foo() = Unit
|
||||
}
|
||||
|
||||
enum class SimpleEnum {
|
||||
ENTRY;
|
||||
|
||||
protected fun foo() = Unit
|
||||
}
|
||||
|
||||
expect enum class ExpEnumClass {
|
||||
ENTRY;
|
||||
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> fun foo()
|
||||
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> val bar: Int
|
||||
}
|
||||
|
||||
actual enum class ActEnumClass {
|
||||
ENTRY;
|
||||
|
||||
actual <!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> fun foo() = Unit
|
||||
|
||||
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> val bar: Int = 42
|
||||
}
|
||||
Generated
+6
@@ -21238,6 +21238,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protectedInExpectActual.kt")
|
||||
public void testProtectedInExpectActual() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/modifiers/protectedInExpectActual.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("redundantTargets.kt")
|
||||
public void testRedundantTargets() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user