[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");
|
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
|
@Test
|
||||||
@TestMetadata("redundantTargets.kt")
|
@TestMetadata("redundantTargets.kt")
|
||||||
public void testRedundantTargets() throws Exception {
|
public void testRedundantTargets() throws Exception {
|
||||||
|
|||||||
+6
@@ -21232,6 +21232,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
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
|
@Test
|
||||||
@TestMetadata("redundantTargets.kt")
|
@TestMetadata("redundantTargets.kt")
|
||||||
public void testRedundantTargets() throws Exception {
|
public void testRedundantTargets() throws Exception {
|
||||||
|
|||||||
+6
@@ -21232,6 +21232,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
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
|
@Test
|
||||||
@TestMetadata("redundantTargets.kt")
|
@TestMetadata("redundantTargets.kt")
|
||||||
public void testRedundantTargets() throws Exception {
|
public void testRedundantTargets() throws Exception {
|
||||||
|
|||||||
+6
@@ -21238,6 +21238,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/modifiers/protected.kt");
|
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
|
@Test
|
||||||
@TestMetadata("redundantTargets.kt")
|
@TestMetadata("redundantTargets.kt")
|
||||||
public void testRedundantTargets() throws Exception {
|
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.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
|
||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -85,7 +83,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
|||||||
val modifier = secondModifier.token
|
val modifier = secondModifier.token
|
||||||
when {
|
when {
|
||||||
!checkTarget(modifierSource, modifier, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
|
!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,
|
modifierSource: KtSourceElement,
|
||||||
modifierToken: KtModifierKeywordToken,
|
modifierToken: KtModifierKeywordToken,
|
||||||
actualParents: List<KotlinTarget>,
|
actualParents: List<KotlinTarget>,
|
||||||
|
parent: FirDeclaration?,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter
|
reporter: DiagnosticReporter
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -251,6 +250,15 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
|||||||
return true
|
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
|
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierToken] ?: return true
|
||||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, context.session.languageVersionSettings) }) 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 {
|
private fun List<KotlinTarget>.firstOrThis(): String {
|
||||||
return firstOrNull()?.description ?: "this"
|
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
|
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
|
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
|
||||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
||||||
trace.report(
|
trace.report(
|
||||||
@@ -237,4 +246,8 @@ object ModifierCheckerCore {
|
|||||||
|
|
||||||
return true
|
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");
|
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
|
@Test
|
||||||
@TestMetadata("redundantTargets.kt")
|
@TestMetadata("redundantTargets.kt")
|
||||||
public void testRedundantTargets() throws Exception {
|
public void testRedundantTargets() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user