[FIR] Disallow qualified access to uninitialized fields in delegate
When using a field as the delegate for a super-interface of an object, make sure uninitialized fields are not allowed. Specifically, disallow access to these fields when referenced via object qualifier. ^KT-56489 Fixed
This commit is contained in:
+7
-4
@@ -96,8 +96,11 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
doNotReportConstantUninitialized: Boolean,
|
doNotReportConstantUninitialized: Boolean,
|
||||||
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>,
|
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>,
|
||||||
) {
|
) {
|
||||||
fun FirQualifiedAccessExpression.hasCorrectReceiver() =
|
fun FirQualifiedAccessExpression.hasMatchingReceiver(): Boolean {
|
||||||
(dispatchReceiver?.unwrapSmartcastExpression() as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
|
val expression = dispatchReceiver?.unwrapSmartcastExpression()
|
||||||
|
return (expression as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver ||
|
||||||
|
(expression as? FirResolvedQualifier)?.symbol == receiver
|
||||||
|
}
|
||||||
|
|
||||||
for (node in graph.nodes) {
|
for (node in graph.nodes) {
|
||||||
when {
|
when {
|
||||||
@@ -115,7 +118,7 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
|
|
||||||
node is VariableAssignmentNode -> {
|
node is VariableAssignmentNode -> {
|
||||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: continue
|
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: continue
|
||||||
if (!symbol.isVal || node.fir.unwrapLValue()?.hasCorrectReceiver() != true || symbol !in properties) continue
|
if (!symbol.isVal || node.fir.unwrapLValue()?.hasMatchingReceiver() != true || symbol !in properties) continue
|
||||||
|
|
||||||
if (getValue(node).values.any { it[symbol]?.canBeRevisited() == true }) {
|
if (getValue(node).values.any { it[symbol]?.canBeRevisited() == true }) {
|
||||||
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
||||||
@@ -133,7 +136,7 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
if (node.fir.resolvedType.hasDiagnosticKind(DiagnosticKind.RecursionInImplicitTypes)) continue
|
if (node.fir.resolvedType.hasDiagnosticKind(DiagnosticKind.RecursionInImplicitTypes)) continue
|
||||||
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: continue
|
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: continue
|
||||||
if (doNotReportConstantUninitialized && symbol.isConst) continue
|
if (doNotReportConstantUninitialized && symbol.isConst) continue
|
||||||
if (!symbol.isLateInit && !symbol.isExternal && node.fir.hasCorrectReceiver() && symbol in properties &&
|
if (!symbol.isLateInit && !symbol.isExternal && node.fir.hasMatchingReceiver() && symbol in properties &&
|
||||||
getValue(node).values.any { it[symbol]?.isDefinitelyVisited() != true }
|
getValue(node).values.any { it[symbol]?.isDefinitelyVisited() != true }
|
||||||
) {
|
) {
|
||||||
reporter.reportOn(node.fir.source, FirErrors.UNINITIALIZED_VARIABLE, symbol, context)
|
reporter.reportOn(node.fir.source, FirErrors.UNINITIALIZED_VARIABLE, symbol, context)
|
||||||
|
|||||||
+4
-8
@@ -1,5 +1,6 @@
|
|||||||
// See KT-15566
|
// WITH_STDLIB
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
// ISSUE: KT-15566, KT-56489
|
||||||
|
|
||||||
import DefaultHttpClient.client
|
import DefaultHttpClient.client
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ class HttpClientImpl : HttpClient
|
|||||||
|
|
||||||
// Below we should have initialization error for both (!) delegates
|
// Below we should have initialization error for both (!) delegates
|
||||||
|
|
||||||
object DefaultHttpClient : HttpClient by client {
|
object DefaultHttpClient : HttpClient by <!UNINITIALIZED_VARIABLE!>client<!> {
|
||||||
val client = HttpClientImpl()
|
val client = HttpClientImpl()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,15 +23,10 @@ object DefaultHttpClientWithFun : HttpClient by fClient() {
|
|||||||
|
|
||||||
private fun fClient() = HttpClientImpl()
|
private fun fClient() = HttpClientImpl()
|
||||||
|
|
||||||
private fun <T> lazy(init: () -> T): kotlin.<!UNRESOLVED_REFERENCE!>Lazy<!><T> {
|
|
||||||
init()
|
|
||||||
null!!
|
|
||||||
}
|
|
||||||
|
|
||||||
object DefaultHttpClientWithBy : HttpClient by client {
|
object DefaultHttpClientWithBy : HttpClient by client {
|
||||||
val client by lazy { HttpClientImpl() }
|
val client by lazy { HttpClientImpl() }
|
||||||
}
|
}
|
||||||
|
|
||||||
object DefaultFqHttpClient : HttpClient by DefaultFqHttpClient.client {
|
object DefaultFqHttpClient : HttpClient by <!UNINITIALIZED_VARIABLE!>DefaultFqHttpClient.client<!> {
|
||||||
val client = HttpClientImpl()
|
val client = HttpClientImpl()
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-7
@@ -1,5 +1,6 @@
|
|||||||
// See KT-15566
|
// WITH_STDLIB
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
// ISSUE: KT-15566, KT-56489
|
||||||
|
|
||||||
import DefaultHttpClient.client
|
import DefaultHttpClient.client
|
||||||
|
|
||||||
@@ -22,15 +23,10 @@ object DefaultHttpClientWithFun : HttpClient by fClient() {
|
|||||||
|
|
||||||
private fun fClient() = HttpClientImpl()
|
private fun fClient() = HttpClientImpl()
|
||||||
|
|
||||||
private fun <T> lazy(init: () -> T): kotlin.<!UNRESOLVED_REFERENCE!>Lazy<!><T> {
|
|
||||||
init()
|
|
||||||
null!!
|
|
||||||
}
|
|
||||||
|
|
||||||
object DefaultHttpClientWithBy : HttpClient by client {
|
object DefaultHttpClientWithBy : HttpClient by client {
|
||||||
val client by lazy { HttpClientImpl() }
|
val client by lazy { HttpClientImpl() }
|
||||||
}
|
}
|
||||||
|
|
||||||
object DefaultFqHttpClient : HttpClient by DefaultFqHttpClient.<!UNINITIALIZED_VARIABLE!>client<!> {
|
object DefaultFqHttpClient : HttpClient by DefaultFqHttpClient.<!UNINITIALIZED_VARIABLE!>client<!> {
|
||||||
val client = HttpClientImpl()
|
val client = HttpClientImpl()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
private fun fClient(): HttpClientImpl
|
private fun fClient(): HttpClientImpl
|
||||||
private fun </*0*/ T> lazy(/*0*/ init: () -> T): [Error type: Unresolved type for kotlin.Lazy<T>]<T>
|
|
||||||
|
|
||||||
public object DefaultFqHttpClient : HttpClient {
|
public object DefaultFqHttpClient : HttpClient {
|
||||||
private constructor DefaultFqHttpClient()
|
private constructor DefaultFqHttpClient()
|
||||||
@@ -21,7 +20,7 @@ public object DefaultHttpClient : HttpClient {
|
|||||||
|
|
||||||
public object DefaultHttpClientWithBy : HttpClient {
|
public object DefaultHttpClientWithBy : HttpClient {
|
||||||
private constructor DefaultHttpClientWithBy()
|
private constructor DefaultHttpClientWithBy()
|
||||||
public final val client: [Error type: Error delegation type for lazy { HttpClientImpl() }]
|
public final val client: HttpClientImpl
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|||||||
Reference in New Issue
Block a user