[FIR] Allow to access uninitialized member properties in non-inPlace lambdas in class initialization
^KT-56696 Fixed ^KT-56408
This commit is contained in:
committed by
Space Team
parent
914acd841f
commit
86af01439c
+6
@@ -5672,6 +5672,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingUninitializedVariableInNonInPlaceLambda.kt")
|
||||||
|
public void testCapturingUninitializedVariableInNonInPlaceLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/capturingUninitializedVariableInNonInPlaceLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("checkInnerLocalDeclarations.kt")
|
@TestMetadata("checkInnerLocalDeclarations.kt")
|
||||||
public void testCheckInnerLocalDeclarations() throws Exception {
|
public void testCheckInnerLocalDeclarations() throws Exception {
|
||||||
|
|||||||
+6
@@ -5678,6 +5678,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingUninitializedVariableInNonInPlaceLambda.kt")
|
||||||
|
public void testCapturingUninitializedVariableInNonInPlaceLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/capturingUninitializedVariableInNonInPlaceLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("checkInnerLocalDeclarations.kt")
|
@TestMetadata("checkInnerLocalDeclarations.kt")
|
||||||
public void testCheckInnerLocalDeclarations() throws Exception {
|
public void testCheckInnerLocalDeclarations() throws Exception {
|
||||||
|
|||||||
+6
@@ -5672,6 +5672,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingUninitializedVariableInNonInPlaceLambda.kt")
|
||||||
|
public void testCapturingUninitializedVariableInNonInPlaceLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/capturingUninitializedVariableInNonInPlaceLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("checkInnerLocalDeclarations.kt")
|
@TestMetadata("checkInnerLocalDeclarations.kt")
|
||||||
public void testCheckInnerLocalDeclarations() throws Exception {
|
public void testCheckInnerLocalDeclarations() throws Exception {
|
||||||
|
|||||||
+27
-3
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.expressions.unwrapLValue
|
|||||||
import org.jetbrains.kotlin.fir.isCatchParameter
|
import org.jetbrains.kotlin.fir.isCatchParameter
|
||||||
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph.Kind
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
|
||||||
@@ -76,7 +77,10 @@ fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
val filtered = properties.filterTo(mutableSetOf()) { it.requiresInitialization(isForClassInitialization) }
|
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, scope = null,
|
||||||
|
isForClassInitialization, doNotReportUninitializedVariable = false, mutableMapOf()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
@@ -86,7 +90,9 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
scope: FirDeclaration?,
|
scope: FirDeclaration?,
|
||||||
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>,
|
isForClassInitialization: Boolean,
|
||||||
|
doNotReportUninitializedVariable: Boolean,
|
||||||
|
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>
|
||||||
) {
|
) {
|
||||||
fun FirQualifiedAccessExpression.hasCorrectReceiver() =
|
fun FirQualifiedAccessExpression.hasCorrectReceiver() =
|
||||||
(dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
|
(dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
|
||||||
@@ -121,6 +127,7 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
}
|
}
|
||||||
|
|
||||||
node is QualifiedAccessNode -> {
|
node is QualifiedAccessNode -> {
|
||||||
|
if (doNotReportUninitializedVariable) continue
|
||||||
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: continue
|
val symbol = node.fir.calleeReference.toResolvedPropertySymbol() ?: continue
|
||||||
if (!symbol.isLateInit && node.fir.hasCorrectReceiver() && symbol in properties &&
|
if (!symbol.isLateInit && node.fir.hasCorrectReceiver() && symbol in properties &&
|
||||||
getValue(node).values.any { it[symbol]?.isDefinitelyVisited() != true }
|
getValue(node).values.any { it[symbol]?.isDefinitelyVisited() != true }
|
||||||
@@ -134,10 +141,27 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
|
|||||||
// needed. The errors on reassignments will be emitted by `FirReassignmentAndInvisibleSetterChecker`.
|
// needed. The errors on reassignments will be emitted by `FirReassignmentAndInvisibleSetterChecker`.
|
||||||
node is CFGNodeWithSubgraphs<*> && (receiver == null || node !== graph.exitNode) -> {
|
node is CFGNodeWithSubgraphs<*> && (receiver == null || node !== graph.exitNode) -> {
|
||||||
for (subGraph in node.subGraphs) {
|
for (subGraph in node.subGraphs) {
|
||||||
|
/*
|
||||||
|
* For class initialization graph we allow to read properties in non-in-place lambdas
|
||||||
|
* even if they may be not initialized at this point, because if lambda is not in-place,
|
||||||
|
* then it most likely will be called after object will be initialized
|
||||||
|
*/
|
||||||
|
val doNotReportForSubGraph = doNotReportUninitializedVariable ||
|
||||||
|
(isForClassInitialization && subGraph.kind.doNotReportUninitializedVariableForClassInitialization)
|
||||||
|
|
||||||
val newScope = subGraph.declaration?.takeIf { !it.evaluatedInPlace } ?: scope
|
val newScope = subGraph.declaration?.takeIf { !it.evaluatedInPlace } ?: scope
|
||||||
checkPropertyAccesses(subGraph, properties, context, reporter, newScope, scopes)
|
checkPropertyAccesses(
|
||||||
|
subGraph, properties, context, reporter, newScope,
|
||||||
|
isForClassInitialization, doNotReportForSubGraph, scopes
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val Kind.doNotReportUninitializedVariableForClassInitialization: Boolean
|
||||||
|
get() = when (this) {
|
||||||
|
Kind.AnonymousFunction, Kind.LocalFunction -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
// DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
import kotlin.contracts.*
|
||||||
|
|
||||||
|
fun capture(block: () -> Unit): String = ""
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun inPlace(block: () -> Unit): String {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consume(x: Any?) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val a = capture { consume(x) }
|
||||||
|
|
||||||
|
val b = inPlace {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val c = object {
|
||||||
|
fun foo() {
|
||||||
|
consume(x) // ok
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(x) // ok
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val objectProp = inPlace {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val d = inPlace {
|
||||||
|
fun localFun() {
|
||||||
|
consume(x) // ok
|
||||||
|
}
|
||||||
|
|
||||||
|
capture {
|
||||||
|
localFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val x = 10
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
// DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
import kotlin.contracts.*
|
||||||
|
|
||||||
|
fun capture(block: () -> Unit): String = ""
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun inPlace(block: () -> Unit): String {
|
||||||
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
block()
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consume(x: Any?) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val a = capture { consume(x) }
|
||||||
|
|
||||||
|
val b = inPlace {
|
||||||
|
consume(x) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(x) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val c = object {
|
||||||
|
fun foo() {
|
||||||
|
consume(x) // ok
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(x) // ok
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
consume(<!UNINITIALIZED_VARIABLE!>x<!>) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(x) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val objectProp = inPlace {
|
||||||
|
consume(x) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
inPlace {
|
||||||
|
consume(x) // error
|
||||||
|
capture { consume(x) } // ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val d = inPlace {
|
||||||
|
fun localFun() {
|
||||||
|
consume(x) // ok
|
||||||
|
}
|
||||||
|
|
||||||
|
capture {
|
||||||
|
localFun()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val x = 10
|
||||||
|
}
|
||||||
-87
@@ -1,87 +0,0 @@
|
|||||||
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,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
fun println(obj: Any?) = obj
|
fun println(obj: Any?) = obj
|
||||||
|
|
||||||
class Demo0 {
|
class Demo0 {
|
||||||
|
|||||||
@@ -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, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>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, UNINITIALIZED_VARIABLE!>f<!>
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>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, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>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, UNINITIALIZED_VARIABLE!>f<!>
|
result += <!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: cycle"), TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>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, UNINITIALIZED_VARIABLE!>f<!>.toString() // Compiler crash
|
result += <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>f<!>.toString() // Compiler crash
|
||||||
"hello"
|
"hello"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, UNINITIALIZED_VARIABLE!>x<!> }
|
val x = { <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>x<!> }
|
||||||
}
|
}
|
||||||
|
|
||||||
//in a package
|
//in a package
|
||||||
|
|||||||
Generated
+6
@@ -5678,6 +5678,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/breakOrContinueInLoopCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("capturingUninitializedVariableInNonInPlaceLambda.kt")
|
||||||
|
public void testCapturingUninitializedVariableInNonInPlaceLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/capturingUninitializedVariableInNonInPlaceLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("checkInnerLocalDeclarations.kt")
|
@TestMetadata("checkInnerLocalDeclarations.kt")
|
||||||
public void testCheckInnerLocalDeclarations() throws Exception {
|
public void testCheckInnerLocalDeclarations() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user