[FE] Check visibilities of expected and actual property setters are compatible
^KT-30905 Fixed
This commit is contained in:
committed by
Space Team
parent
9044dfe394
commit
c718c77c43
+6
@@ -127,6 +127,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("varSetterVisibility.kt")
|
||||||
|
public void testVarSetterVisibility() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/varSetterVisibility.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+6
@@ -127,6 +127,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("varSetterVisibility.kt")
|
||||||
|
public void testVarSetterVisibility() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/varSetterVisibility.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+13
@@ -523,10 +523,23 @@ object FirExpectActualResolver {
|
|||||||
!equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCompatibility.Incompatible.PropertyKind
|
!equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCompatibility.Incompatible.PropertyKind
|
||||||
!equalBy(expected, actual) { p -> p.isLateInit } -> ExpectActualCompatibility.Incompatible.PropertyLateinitModifier
|
!equalBy(expected, actual) { p -> p.isLateInit } -> ExpectActualCompatibility.Incompatible.PropertyLateinitModifier
|
||||||
expected.isConst && !actual.isConst -> ExpectActualCompatibility.Incompatible.PropertyConstModifier
|
expected.isConst && !actual.isConst -> ExpectActualCompatibility.Incompatible.PropertyConstModifier
|
||||||
|
!arePropertySettersWithCompatibleVisibilities(expected, actual) -> ExpectActualCompatibility.Incompatible.PropertySetterVisibility
|
||||||
else -> ExpectActualCompatibility.Compatible
|
else -> ExpectActualCompatibility.Compatible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun arePropertySettersWithCompatibleVisibilities(
|
||||||
|
expected: FirPropertySymbol,
|
||||||
|
actual: FirPropertySymbol,
|
||||||
|
): Boolean {
|
||||||
|
val expectedSetterStatus = expected.setterSymbol?.resolvedStatus
|
||||||
|
val actualSetterStatus = actual.setterSymbol?.resolvedStatus
|
||||||
|
if (expectedSetterStatus == null || actualSetterStatus == null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return areDeclarationsWithCompatibleVisibilities(expectedSetterStatus, actualSetterStatus)
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------- Utils ----------------------------------------
|
// ---------------------------------------- Utils ----------------------------------------
|
||||||
|
|
||||||
private fun List<FirValueParameterSymbol>.toTypeList(substitutor: ConeSubstitutor): List<ConeKotlinType> {
|
private fun List<FirValueParameterSymbol>.toTypeList(substitutor: ConeSubstitutor): List<ConeKotlinType> {
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ object ClassicPositioningStrategies {
|
|||||||
ExpectActualCompatibility.Incompatible.Visibility -> {
|
ExpectActualCompatibility.Incompatible.Visibility -> {
|
||||||
element.visibilityModifier()
|
element.visibilityModifier()
|
||||||
}
|
}
|
||||||
|
ExpectActualCompatibility.Incompatible.PropertySetterVisibility -> {
|
||||||
|
(element as? KtProperty)?.setter?.modifierList
|
||||||
|
}
|
||||||
}?.let { markElement(it) } ?: ACTUAL_DECLARATION_NAME.mark(element)
|
}?.let { markElement(it) } ?: ACTUAL_DECLARATION_NAME.mark(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -370,10 +370,20 @@ object ExpectedActualResolver {
|
|||||||
!equalBy(expected, actual) { p -> p.isVar } -> Incompatible.PropertyKind
|
!equalBy(expected, actual) { p -> p.isVar } -> Incompatible.PropertyKind
|
||||||
!equalBy(expected, actual) { p -> p.isLateInit } -> Incompatible.PropertyLateinitModifier
|
!equalBy(expected, actual) { p -> p.isLateInit } -> Incompatible.PropertyLateinitModifier
|
||||||
expected.isConst && !actual.isConst -> Incompatible.PropertyConstModifier
|
expected.isConst && !actual.isConst -> Incompatible.PropertyConstModifier
|
||||||
|
!arePropertySettersWithCompatibleVisibilities(expected, actual) -> Incompatible.PropertySetterVisibility
|
||||||
else -> Compatible
|
else -> Compatible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun arePropertySettersWithCompatibleVisibilities(expected: PropertyDescriptor, actual: PropertyDescriptor): Boolean {
|
||||||
|
val expectedSetter = expected.setter
|
||||||
|
val actualSetter = actual.setter
|
||||||
|
if (expectedSetter == null || actualSetter == null) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return areDeclarationsWithCompatibleVisibilities(expectedSetter, actualSetter)
|
||||||
|
}
|
||||||
|
|
||||||
private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor): ExpectActualCompatibility<MemberDescriptor> {
|
private fun areCompatibleClassifiers(a: ClassDescriptor, other: ClassifierDescriptor): ExpectActualCompatibility<MemberDescriptor> {
|
||||||
// Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name
|
// Can't check FQ names here because nested expected class may be implemented via actual typealias's expansion with the other FQ name
|
||||||
assert(a.name == other.name) { "This function should be invoked only for declarations with the same name: $a, $other" }
|
assert(a.name == other.name) { "This function should be invoked only for declarations with the same name: $a, $other" }
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// MODULE: m1-common
|
||||||
|
// FILE: common.kt
|
||||||
|
expect var v1: Boolean
|
||||||
|
|
||||||
|
expect var v2: Boolean
|
||||||
|
internal set
|
||||||
|
|
||||||
|
expect var v3: Boolean
|
||||||
|
internal set
|
||||||
|
|
||||||
|
expect open class C {
|
||||||
|
var foo: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
expect open class C2 {
|
||||||
|
var foo: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: m1-jvm()()(m1-common)
|
||||||
|
// FILE: jvm.kt
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>actual var v1: Boolean = false
|
||||||
|
private set<!>
|
||||||
|
|
||||||
|
actual var v2: Boolean = false
|
||||||
|
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>actual var v3: Boolean = false
|
||||||
|
private set<!>
|
||||||
|
|
||||||
|
actual open class C {
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>actual var foo: Boolean = false
|
||||||
|
protected set<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class C2Typealias {
|
||||||
|
var foo: Boolean = false
|
||||||
|
protected set
|
||||||
|
}
|
||||||
|
|
||||||
|
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>C2<!> = C2Typealias
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// MODULE: m1-common
|
||||||
|
// FILE: common.kt
|
||||||
|
expect var v1: Boolean
|
||||||
|
|
||||||
|
expect var v2: Boolean
|
||||||
|
internal set
|
||||||
|
|
||||||
|
expect var v3: Boolean
|
||||||
|
internal set
|
||||||
|
|
||||||
|
expect open class C {
|
||||||
|
var foo: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
expect open class C2 {
|
||||||
|
var foo: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: m1-jvm()()(m1-common)
|
||||||
|
// FILE: jvm.kt
|
||||||
|
actual var v1: Boolean = false
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>private<!> set
|
||||||
|
|
||||||
|
actual var v2: Boolean = false
|
||||||
|
|
||||||
|
actual var v3: Boolean = false
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>private<!> set
|
||||||
|
|
||||||
|
actual open class C {
|
||||||
|
actual var foo: Boolean = false
|
||||||
|
<!ACTUAL_WITHOUT_EXPECT!>protected<!> set
|
||||||
|
}
|
||||||
|
|
||||||
|
open class C2Typealias {
|
||||||
|
var foo: Boolean = false
|
||||||
|
protected set
|
||||||
|
}
|
||||||
|
|
||||||
|
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>C2<!> = C2Typealias
|
||||||
Generated
+6
@@ -21912,6 +21912,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
runTest("compiler/testData/diagnostics/tests/multiplatform/smartcastOnMemberPropertyFromCommonClass.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("varSetterVisibility.kt")
|
||||||
|
public void testVarSetterVisibility() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/multiplatform/varSetterVisibility.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+1
@@ -58,6 +58,7 @@ sealed class ExpectActualCompatibility<out D> {
|
|||||||
object PropertyKind : Incompatible<Nothing>("property kinds are different (val vs var)")
|
object PropertyKind : Incompatible<Nothing>("property kinds are different (val vs var)")
|
||||||
object PropertyLateinitModifier : Incompatible<Nothing>("modifiers are different (lateinit)")
|
object PropertyLateinitModifier : Incompatible<Nothing>("modifiers are different (lateinit)")
|
||||||
object PropertyConstModifier : Incompatible<Nothing>("modifiers are different (const)")
|
object PropertyConstModifier : Incompatible<Nothing>("modifiers are different (const)")
|
||||||
|
object PropertySetterVisibility : Incompatible<Nothing>("setter visibility is different")
|
||||||
|
|
||||||
// Classifiers
|
// Classifiers
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user