[FIR] Property accessors are not part of class initialization
When checking for class val property reassignment diagnostic, property initializers should be treated as part of the class initialization. However, property accessors should not. Previously, only the property itself was checked for both of these situations and resulted in not reporting diagnostic within property accessors. #KT-59744 Fixed
This commit is contained in:
+27
@@ -28,6 +28,33 @@ FILE: reassignOfNonLocalProperty_initializedProperties.kt
|
||||
)
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
public final var b: R|kotlin/String| = String(hello)
|
||||
public get(): R|kotlin/String| {
|
||||
this@R|/Some|.R|/Some.x| = String(error)
|
||||
this@R|/Some|.R|/y| = String(error)
|
||||
R|/z| = String(error)
|
||||
^ this@R|/Some|.F|/Some.b|
|
||||
}
|
||||
public set(value: R|kotlin/String|): R|kotlin/Unit| {
|
||||
this@R|/Some|.R|/Some.x| = R|<local>/value|
|
||||
this@R|/Some|.R|/y| = R|<local>/value|
|
||||
R|/z| = R|<local>/value|
|
||||
this@R|/Some|.F|/Some.b| = R|<local>/value|
|
||||
}
|
||||
|
||||
public final var c: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
this@R|/Some|.R|/Some.x| = String(error)
|
||||
this@R|/Some|.R|/y| = String(error)
|
||||
R|/z| = String(error)
|
||||
^ String(hello)
|
||||
}
|
||||
public set(value: R|kotlin/String|): R|kotlin/Unit| {
|
||||
this@R|/Some|.R|/Some.x| = R|<local>/value|
|
||||
this@R|/Some|.R|/y| = R|<local>/value|
|
||||
R|/z| = R|<local>/value|
|
||||
}
|
||||
|
||||
public final fun test_1(): R|kotlin/Unit| {
|
||||
this@R|/Some|.R|/Some.x| = String(error)
|
||||
this@R|/Some|.R|/y| = String(error)
|
||||
|
||||
compiler/fir/analysis-tests/testData/resolve/cfa/reassignOfNonLocalProperty_initializedProperties.kt
Vendored
+28
-1
@@ -1,4 +1,4 @@
|
||||
// ISSUE: KT-55493
|
||||
// ISSUE: KT-55493, KT-59744
|
||||
// WITH_STDLIB
|
||||
|
||||
val z: String = "ok"
|
||||
@@ -22,6 +22,33 @@ class Some {
|
||||
"hello"
|
||||
}
|
||||
|
||||
var b: String = "hello"
|
||||
get() {
|
||||
<!VAL_REASSIGNMENT!>x<!> = "error"
|
||||
<!VAL_REASSIGNMENT!>y<!> = "error"
|
||||
<!VAL_REASSIGNMENT!>z<!> = "error"
|
||||
return field
|
||||
}
|
||||
set(value) {
|
||||
<!VAL_REASSIGNMENT!>x<!> = value
|
||||
<!VAL_REASSIGNMENT!>y<!> = value
|
||||
<!VAL_REASSIGNMENT!>z<!> = value
|
||||
field = value
|
||||
}
|
||||
|
||||
var c: String
|
||||
get() {
|
||||
<!VAL_REASSIGNMENT!>x<!> = "error"
|
||||
<!VAL_REASSIGNMENT!>y<!> = "error"
|
||||
<!VAL_REASSIGNMENT!>z<!> = "error"
|
||||
return "hello"
|
||||
}
|
||||
set(value) {
|
||||
<!VAL_REASSIGNMENT!>x<!> = value
|
||||
<!VAL_REASSIGNMENT!>y<!> = value
|
||||
<!VAL_REASSIGNMENT!>z<!> = value
|
||||
}
|
||||
|
||||
fun test_1() {
|
||||
<!VAL_REASSIGNMENT!>x<!> = "error"
|
||||
<!VAL_REASSIGNMENT!>y<!> = "error"
|
||||
|
||||
+21
-10
@@ -148,18 +148,29 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
||||
|
||||
private fun isInOwnersInitializer(receiver: FirExpression, context: CheckerContext): Boolean {
|
||||
val uninitializedThisSymbol = (receiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol ?: return false
|
||||
var foundInitializer = false
|
||||
for ((i, declaration) in context.containingDeclarations.withIndex()) {
|
||||
if (declaration is FirClass) {
|
||||
foundInitializer = if (context.containingDeclarations.getOrNull(i + 1)?.evaluatedInPlace == false) {
|
||||
// In member function of a class, assume all outer classes are already initialized
|
||||
// by the time this function is called.
|
||||
false
|
||||
} else {
|
||||
foundInitializer || declaration.symbol == uninitializedThisSymbol
|
||||
val containingDeclarations = context.containingDeclarations
|
||||
|
||||
val index = containingDeclarations.indexOfFirst { it is FirClass && it.symbol == uninitializedThisSymbol }
|
||||
if (index == -1) return false
|
||||
|
||||
for (i in index until containingDeclarations.size) {
|
||||
if (containingDeclarations[i] is FirClass) {
|
||||
// Properties need special consideration as some parts are evaluated in-place (initializers) and others are not (accessors).
|
||||
// So it is not enough to just check the FirProperty - which is treated as in-place - but the following declaration needs to
|
||||
// be checked if and only if it is a property accessor.
|
||||
val container = when (val next = containingDeclarations.getOrNull(i + 1)) {
|
||||
is FirProperty -> containingDeclarations.getOrNull(i + 2)?.takeIf { it is FirPropertyAccessor } ?: next
|
||||
else -> next
|
||||
}
|
||||
|
||||
// In member function of a class, assume all outer classes are already initialized
|
||||
// by the time this function is called.
|
||||
if (container?.evaluatedInPlace == false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundInitializer
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user