[FIR] Run CFA for member properties even if they have initializer
^KT-56678 Fixed ^KT-56682 Fixed
This commit is contained in:
committed by
Space Team
parent
de84cb8038
commit
c87e489dc9
+12
@@ -5696,6 +5696,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("delegatedMemberProperyWriteInInit.kt")
|
||||||
|
public void testDelegatedMemberProperyWriteInInit() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/delegatedMemberProperyWriteInInit.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
||||||
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
||||||
@@ -6116,6 +6122,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("uninintializedProperyWithDirectAndDelayedInitialization.kt")
|
||||||
|
public void testUninintializedProperyWithDirectAndDelayedInitialization() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninintializedProperyWithDirectAndDelayedInitialization.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
||||||
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
||||||
|
|||||||
+12
@@ -5702,6 +5702,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("delegatedMemberProperyWriteInInit.kt")
|
||||||
|
public void testDelegatedMemberProperyWriteInInit() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/delegatedMemberProperyWriteInInit.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
||||||
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
||||||
@@ -6122,6 +6128,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("uninintializedProperyWithDirectAndDelayedInitialization.kt")
|
||||||
|
public void testUninintializedProperyWithDirectAndDelayedInitialization() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninintializedProperyWithDirectAndDelayedInitialization.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
||||||
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
||||||
|
|||||||
+12
@@ -5696,6 +5696,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("delegatedMemberProperyWriteInInit.kt")
|
||||||
|
public void testDelegatedMemberProperyWriteInInit() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/delegatedMemberProperyWriteInInit.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
||||||
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
||||||
@@ -6116,6 +6122,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("uninintializedProperyWithDirectAndDelayedInitialization.kt")
|
||||||
|
public void testUninintializedProperyWithDirectAndDelayedInitialization() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninintializedProperyWithDirectAndDelayedInitialization.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
||||||
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
||||||
|
|||||||
+28
-7
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
|
|||||||
|
|
||||||
object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChecker() {
|
object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChecker() {
|
||||||
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
|
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
|
||||||
data.checkPropertyAccesses(context, reporter)
|
data.checkPropertyAccesses(isForClassInitialization = false, context, reporter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,15 +44,36 @@ val FirDeclaration.evaluatedInPlace: Boolean
|
|||||||
else -> true // property initializer, etc.
|
else -> true // property initializer, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
/**
|
||||||
val FirPropertySymbol.requiresInitialization: Boolean
|
* [isForClassInitialization] means that caller is interested in member property in the scope
|
||||||
get() = this !is FirSyntheticPropertySymbol && !hasInitializer && !hasExplicitBackingField &&
|
* of class initialization section. In this case the fact that property has initializer does
|
||||||
hasBackingField && fir.isCatchParameter != true
|
* not mean that it's safe to access this property in any place:
|
||||||
|
*
|
||||||
|
* class A {
|
||||||
|
* val b = a // a is not initialized here
|
||||||
|
* val a = 10
|
||||||
|
* val c = a // but initialized here
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
fun PropertyInitializationInfoData.checkPropertyAccesses(context: CheckerContext, reporter: DiagnosticReporter) {
|
@OptIn(SymbolInternals::class)
|
||||||
|
fun FirPropertySymbol.requiresInitialization(isForClassInitialization: Boolean): Boolean {
|
||||||
|
val hasImplicitBackingField = !hasExplicitBackingField && hasBackingField
|
||||||
|
return when {
|
||||||
|
this is FirSyntheticPropertySymbol -> false
|
||||||
|
isForClassInitialization -> hasDelegate || hasImplicitBackingField
|
||||||
|
else -> !hasInitializer && hasImplicitBackingField && fir.isCatchParameter != true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PropertyInitializationInfoData.checkPropertyAccesses(
|
||||||
|
isForClassInitialization: Boolean,
|
||||||
|
context: CheckerContext,
|
||||||
|
reporter: DiagnosticReporter
|
||||||
|
) {
|
||||||
// If a property has an initializer (or does not need one), then any reads are OK while any writes are OK
|
// If a property has an initializer (or does not need one), then any reads are OK while any writes are OK
|
||||||
// if it's a `var` and bad if it's a `val`. `FirReassignmentAndInvisibleSetterChecker` does this without a CFG.
|
// if it's a `var` and bad if it's a `val`. `FirReassignmentAndInvisibleSetterChecker` does this without a CFG.
|
||||||
val filtered = properties.filterTo(mutableSetOf()) { it.requiresInitialization }
|
val filtered = properties.filterTo(mutableSetOf()) { it.requiresInitialization(isForClassInitialization) }
|
||||||
if (filtered.isEmpty()) return
|
if (filtered.isEmpty()) return
|
||||||
|
|
||||||
checkPropertyAccesses(graph, filtered, context, reporter, null, mutableMapOf())
|
checkPropertyAccesses(graph, filtered, context, reporter, null, mutableMapOf())
|
||||||
|
|||||||
+12
@@ -73,6 +73,18 @@ class PropertyInitializationInfoCollector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitPropertyInitializerExitNode(
|
||||||
|
node: PropertyInitializerExitNode,
|
||||||
|
data: PathAwareControlFlowInfo<PropertyInitializationInfo>
|
||||||
|
): PathAwareControlFlowInfo<PropertyInitializationInfo> {
|
||||||
|
// If member property initializer is empty (there are no nodes between enter and exit node)
|
||||||
|
// then property is not initialized in its declaration
|
||||||
|
// Otherwise it is
|
||||||
|
val dataForNode = visitNode(node, data)
|
||||||
|
if (node.firstPreviousNode is PropertyInitializerEnterNode) return dataForNode
|
||||||
|
return overwriteRange(dataForNode, node.fir.symbol, EventOccurrencesRange.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// Data flows of declared/assigned variables in loops
|
// Data flows of declared/assigned variables in loops
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|||||||
+2
-2
@@ -47,12 +47,12 @@ object FirMemberPropertiesChecker : FirClassChecker() {
|
|||||||
private fun FirClass.collectInitializationInfo(context: CheckerContext, reporter: DiagnosticReporter): PropertyInitializationInfo? {
|
private fun FirClass.collectInitializationInfo(context: CheckerContext, reporter: DiagnosticReporter): PropertyInitializationInfo? {
|
||||||
val graph = (this as? FirControlFlowGraphOwner)?.controlFlowGraphReference?.controlFlowGraph ?: return null
|
val graph = (this as? FirControlFlowGraphOwner)?.controlFlowGraphReference?.controlFlowGraph ?: return null
|
||||||
val memberPropertySymbols = declarations.mapNotNullTo(mutableSetOf()) {
|
val memberPropertySymbols = declarations.mapNotNullTo(mutableSetOf()) {
|
||||||
(it.symbol as? FirPropertySymbol)?.takeIf { symbol -> symbol.requiresInitialization }
|
(it.symbol as? FirPropertySymbol)?.takeIf { symbol -> symbol.requiresInitialization(isForClassInitialization = true) }
|
||||||
}
|
}
|
||||||
if (memberPropertySymbols.isEmpty()) return null
|
if (memberPropertySymbols.isEmpty()) return null
|
||||||
// TODO: merge with `FirPropertyInitializationAnalyzer` for fewer passes.
|
// TODO: merge with `FirPropertyInitializationAnalyzer` for fewer passes.
|
||||||
val data = PropertyInitializationInfoData(memberPropertySymbols, symbol, graph)
|
val data = PropertyInitializationInfoData(memberPropertySymbols, symbol, graph)
|
||||||
data.checkPropertyAccesses(context, reporter)
|
data.checkPropertyAccesses(isForClassInitialization = true, context, reporter)
|
||||||
return data.getValue(graph.exitNode)[NormalPath]
|
return data.getValue(graph.exitNode)[NormalPath]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -138,7 +138,8 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
|
|||||||
if (property.isVar) return
|
if (property.isVar) return
|
||||||
// Assignments of uninitialized `val`s must be checked via CFG, since the first one is OK.
|
// Assignments of uninitialized `val`s must be checked via CFG, since the first one is OK.
|
||||||
// See `FirPropertyInitializationAnalyzer` for locals and `FirMemberPropertiesChecker` for backing fields in initializers.
|
// See `FirPropertyInitializationAnalyzer` for locals and `FirMemberPropertiesChecker` for backing fields in initializers.
|
||||||
if (property.requiresInitialization && (property.isLocal || isInOwnersInitializer(expression.dispatchReceiver, context))) return
|
if (property.isLocal && property.requiresInitialization(isForClassInitialization = false)) return
|
||||||
|
if (isInOwnersInitializer(expression.dispatchReceiver, context) && property.requiresInitialization(isForClassInitialization = true)) return
|
||||||
|
|
||||||
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, property, context)
|
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, property, context)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -43,7 +43,7 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReassignedVariableCollector(val data: PropertyInitializationInfoData, ) : ControlFlowGraphVisitorVoid() {
|
private class ReassignedVariableCollector(val data: PropertyInitializationInfoData) : ControlFlowGraphVisitorVoid() {
|
||||||
private val reassigned = mutableSetOf<FirPropertySymbol>()
|
private val reassigned = mutableSetOf<FirPropertySymbol>()
|
||||||
|
|
||||||
override fun visitNode(node: CFGNode<*>) {}
|
override fun visitNode(node: CFGNode<*>) {}
|
||||||
@@ -51,7 +51,7 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() {
|
|||||||
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
||||||
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return
|
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return
|
||||||
if (symbol.isVar && symbol.source?.kind !is KtFakeSourceElementKind && symbol in data.properties &&
|
if (symbol.isVar && symbol.source?.kind !is KtFakeSourceElementKind && symbol in data.properties &&
|
||||||
(!symbol.requiresInitialization || data.getValue(node).values.any { it[symbol]?.canBeRevisited() == true })
|
(!symbol.requiresInitialization(isForClassInitialization = data.graph.kind == ControlFlowGraph.Kind.Class) || data.getValue(node).values.any { it[symbol]?.canBeRevisited() == true })
|
||||||
) {
|
) {
|
||||||
reassigned.add(symbol)
|
reassigned.add(symbol)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -255,8 +255,8 @@ class Outer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ForwardAccessToBackingField() { //kt-147
|
class ForwardAccessToBackingField() { //kt-147
|
||||||
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!> // error
|
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>a<!> // error
|
||||||
val b = c // error
|
val b = <!UNINITIALIZED_VARIABLE!>c<!> // error
|
||||||
val c = 1
|
val c = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
interface Delegate<V> {
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): V = null!!
|
||||||
|
|
||||||
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <V> delegate(): Delegate<V> = null!!
|
||||||
|
fun consume(x: Any?) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>)
|
||||||
|
<!INITIALIZATION_BEFORE_DECLARATION!>x<!> = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
val x: Int by delegate()
|
||||||
|
|
||||||
|
init {
|
||||||
|
<!VAL_REASSIGNMENT!>x<!> = 10
|
||||||
|
consume(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>)
|
||||||
|
<!INITIALIZATION_BEFORE_DECLARATION!>x<!> = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
var x: Int by delegate()
|
||||||
|
|
||||||
|
init {
|
||||||
|
x = 10
|
||||||
|
consume(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
interface Delegate<V> {
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): V = null!!
|
||||||
|
|
||||||
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <V> delegate(): Delegate<V> = null!!
|
||||||
|
fun consume(x: Any?) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>)
|
||||||
|
<!VAL_REASSIGNMENT!>x<!> = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
val x: Int by delegate()
|
||||||
|
|
||||||
|
init {
|
||||||
|
x = 10
|
||||||
|
consume(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>)
|
||||||
|
<!INITIALIZATION_BEFORE_DECLARATION!>x<!> = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
var x: Int by delegate()
|
||||||
|
|
||||||
|
init {
|
||||||
|
x = 10
|
||||||
|
consume(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
// See also KT-10869: Accessing lazy properties from init causes IllegalArgumentException
|
// ISSUE: KT-10869, KT-56682
|
||||||
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@@ -9,14 +9,14 @@ class CustomDelegate {
|
|||||||
class Kaboom() {
|
class Kaboom() {
|
||||||
// Here and below we should have errors for simple AND delegated
|
// Here and below we should have errors for simple AND delegated
|
||||||
init {
|
init {
|
||||||
delegated.hashCode()
|
<!UNINITIALIZED_VARIABLE!>delegated<!>.hashCode()
|
||||||
simple.hashCode()
|
<!UNINITIALIZED_VARIABLE!>simple<!>.hashCode()
|
||||||
withGetter.hashCode()
|
withGetter.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
val other = delegated
|
val other = <!UNINITIALIZED_VARIABLE!>delegated<!>
|
||||||
|
|
||||||
val another = simple
|
val another = <!UNINITIALIZED_VARIABLE!>simple<!>
|
||||||
|
|
||||||
val something = withGetter
|
val something = withGetter
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// See also KT-10869: Accessing lazy properties from init causes IllegalArgumentException
|
// ISSUE: KT-10869, KT-56682
|
||||||
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
//KT-897 Don't allow assignment to a property before it is defined
|
|
||||||
|
|
||||||
package kt897
|
|
||||||
|
|
||||||
class A() {
|
|
||||||
init {
|
|
||||||
<!INITIALIZATION_BEFORE_DECLARATION, VAL_REASSIGNMENT!>i<!> = 11
|
|
||||||
}
|
|
||||||
val i : Int? = null // must be an error
|
|
||||||
|
|
||||||
init {
|
|
||||||
<!INITIALIZATION_BEFORE_DECLARATION!>j<!> = 1
|
|
||||||
}
|
|
||||||
var j : Int = 2
|
|
||||||
|
|
||||||
init {
|
|
||||||
<!INITIALIZATION_BEFORE_DECLARATION!>k<!> = 3
|
|
||||||
}
|
|
||||||
val k : Int
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
//KT-897 Don't allow assignment to a property before it is defined
|
//KT-897 Don't allow assignment to a property before it is defined
|
||||||
|
|
||||||
package kt897
|
package kt897
|
||||||
|
|||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
fun println(obj: Any?) = obj
|
||||||
|
|
||||||
|
class Demo0 {
|
||||||
|
private val some = object {
|
||||||
|
fun foo() {
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Demo1 {
|
||||||
|
private val some = object {
|
||||||
|
fun foo() {
|
||||||
|
if (state)
|
||||||
|
state = true
|
||||||
|
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Demo1A {
|
||||||
|
fun foo() {
|
||||||
|
if (state)
|
||||||
|
state = true
|
||||||
|
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Demo2 {
|
||||||
|
private val some = object {
|
||||||
|
fun foo() {
|
||||||
|
if (state)
|
||||||
|
state = true
|
||||||
|
else
|
||||||
|
state = false
|
||||||
|
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Demo3 {
|
||||||
|
private val some = run {
|
||||||
|
if (state)
|
||||||
|
state = true
|
||||||
|
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> exec(f: () -> T): T = f()
|
||||||
|
|
||||||
|
class Demo4 {
|
||||||
|
private val some = exec {
|
||||||
|
if (<!UNINITIALIZED_VARIABLE!>state<!>)
|
||||||
|
state = true
|
||||||
|
|
||||||
|
println(<!UNINITIALIZED_VARIABLE!>state<!>)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Demo5 {
|
||||||
|
private var state: Boolean = true
|
||||||
|
|
||||||
|
private val some = object {
|
||||||
|
fun foo() {
|
||||||
|
if (state)
|
||||||
|
state = true
|
||||||
|
|
||||||
|
println(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
fun println(obj: Any?) = obj
|
fun println(obj: Any?) = obj
|
||||||
|
|
||||||
class Demo0 {
|
class Demo0 {
|
||||||
|
|||||||
Vendored
+5
-5
@@ -11,22 +11,22 @@ class TestFunctionLiteral {
|
|||||||
open class A(val a: A)
|
open class A(val a: A)
|
||||||
|
|
||||||
class TestObjectLiteral {
|
class TestObjectLiteral {
|
||||||
val obj: A = object: A(obj) {
|
val obj: A = object: A(<!UNINITIALIZED_VARIABLE!>obj<!>) {
|
||||||
init {
|
init {
|
||||||
val x = obj
|
val x = <!UNINITIALIZED_VARIABLE!>obj<!>
|
||||||
}
|
}
|
||||||
fun foo() {
|
fun foo() {
|
||||||
val y = obj
|
val y = obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val obj1: A = l@ ( object: A(obj1) {
|
val obj1: A = l@ ( object: A(<!UNINITIALIZED_VARIABLE!>obj1<!>) {
|
||||||
init {
|
init {
|
||||||
val x = obj1
|
val x = <!UNINITIALIZED_VARIABLE!>obj1<!>
|
||||||
}
|
}
|
||||||
fun foo() = obj1
|
fun foo() = obj1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestOther {
|
class TestOther {
|
||||||
val x: Int = x + 1
|
val x: Int = <!UNINITIALIZED_VARIABLE!>x<!> + 1
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -4,8 +4,8 @@ val a : Int = b
|
|||||||
val b : Int = a + b
|
val b : Int = a + b
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
val a : Int = b
|
val a : Int = <!UNINITIALIZED_VARIABLE!>b<!>
|
||||||
val b : Int = a + b
|
val b : Int = a + <!UNINITIALIZED_VARIABLE!>b<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// ISSUE: KT-56678
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val b = <!UNINITIALIZED_VARIABLE!>a<!>
|
||||||
|
val a = 1
|
||||||
|
val c = a
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
val b = <!UNINITIALIZED_VARIABLE!>a<!>
|
||||||
|
val a: Int
|
||||||
|
val c = <!UNINITIALIZED_VARIABLE!>a<!>
|
||||||
|
init {
|
||||||
|
a = 1
|
||||||
|
}
|
||||||
|
val d = a
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
object DelegateTest {
|
object DelegateTest {
|
||||||
var result = ""
|
var result = ""
|
||||||
val f by lazy {
|
val f by lazy {
|
||||||
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>.toString() // Compiler crash
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ object DelegateTest {
|
|||||||
object DelegateTest2 {
|
object DelegateTest2 {
|
||||||
var result = ""
|
var result = ""
|
||||||
val f by lazy {
|
val f by lazy {
|
||||||
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>f<!>
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
object DelegateTest {
|
object DelegateTest {
|
||||||
var result = ""
|
var result = ""
|
||||||
val f by lazy {
|
val f by lazy {
|
||||||
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>.toString() // Compiler crash
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ object DelegateTest {
|
|||||||
object DelegateTest2 {
|
object DelegateTest2 {
|
||||||
var result = ""
|
var result = ""
|
||||||
val f by lazy {
|
val f by lazy {
|
||||||
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>f<!>
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
object DelegateTest {
|
object DelegateTest {
|
||||||
var result = ""
|
var result = ""
|
||||||
val f by lazy {
|
val f by lazy {
|
||||||
result += <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>.toString() // Compiler crash
|
result += <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
private val y = object {
|
private val y = object {
|
||||||
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>y<!>;
|
val a = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>y<!>;
|
||||||
}
|
}
|
||||||
|
|
||||||
val z = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>y.a<!>;
|
val z = <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>y.a<!>;
|
||||||
@@ -17,9 +17,9 @@ object A {
|
|||||||
class Test2 {
|
class Test2 {
|
||||||
private val a = object {
|
private val a = object {
|
||||||
init {
|
init {
|
||||||
b + 1
|
<!UNINITIALIZED_VARIABLE!>b<!> + 1
|
||||||
}
|
}
|
||||||
val x = b
|
val x = <!UNINITIALIZED_VARIABLE!>b<!>
|
||||||
val y = 1
|
val y = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ fun bar2() = {
|
|||||||
//properties
|
//properties
|
||||||
//in a class
|
//in a class
|
||||||
class A() {
|
class A() {
|
||||||
val x = { <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>x<!> }
|
val x = { <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, UNINITIALIZED_VARIABLE!>x<!> }
|
||||||
}
|
}
|
||||||
|
|
||||||
//in a package
|
//in a package
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ class A(val w: Int) {
|
|||||||
val x: Int
|
val x: Int
|
||||||
val useUnitialized = <!UNINITIALIZED_VARIABLE!>x<!> +
|
val useUnitialized = <!UNINITIALIZED_VARIABLE!>x<!> +
|
||||||
<!UNINITIALIZED_VARIABLE!>y<!> +
|
<!UNINITIALIZED_VARIABLE!>y<!> +
|
||||||
v
|
<!UNINITIALIZED_VARIABLE!>v<!>
|
||||||
var y: Int
|
var y: Int
|
||||||
val v = -1
|
val v = -1
|
||||||
val useInitialized = useUnitialized + v + w
|
val useInitialized = useUnitialized + v + w
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ class A {
|
|||||||
val x: Int
|
val x: Int
|
||||||
val useUnitialized = <!UNINITIALIZED_VARIABLE!>x<!> + // reported on each secondary constructor
|
val useUnitialized = <!UNINITIALIZED_VARIABLE!>x<!> + // reported on each secondary constructor
|
||||||
<!UNINITIALIZED_VARIABLE!>y<!> +
|
<!UNINITIALIZED_VARIABLE!>y<!> +
|
||||||
v
|
<!UNINITIALIZED_VARIABLE!>v<!>
|
||||||
var y: Int
|
var y: Int
|
||||||
val v = -1
|
val v = -1
|
||||||
|
|
||||||
|
|||||||
Generated
+12
@@ -5702,6 +5702,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturnInWhen.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("delegatedMemberProperyWriteInInit.kt")
|
||||||
|
public void testDelegatedMemberProperyWriteInInit() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/delegatedMemberProperyWriteInInit.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
@TestMetadata("delegatedPropertyEarlyAccess.kt")
|
||||||
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
public void testDelegatedPropertyEarlyAccess() throws Exception {
|
||||||
@@ -6122,6 +6128,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/tryWithAssignmentUsedInCatch.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("uninintializedProperyWithDirectAndDelayedInitialization.kt")
|
||||||
|
public void testUninintializedProperyWithDirectAndDelayedInitialization() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninintializedProperyWithDirectAndDelayedInitialization.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
@TestMetadata("uninitializedCompanionOfEnum_after.kt")
|
||||||
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
public void testUninitializedCompanionOfEnum_after() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user