diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/Utils.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/Utils.kt index a6aedc54a..f380e2e23 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/Utils.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/Utils.kt @@ -329,3 +329,20 @@ internal inline fun runOutsideIgnoredSection(descriptor: ThreadDescriptor?, internal const val LINCHECK_PACKAGE_NAME = "org.jetbrains.kotlinx.lincheck." internal const val LINCHECK_RUNNER_PACKAGE_NAME = "org.jetbrains.kotlinx.lincheck.runner." + +internal fun Class.newDefaultInstance(): T { + @Suppress("UNCHECKED_CAST") + val constructor = this.declaredConstructors.singleOrNull { it.parameterCount == 0 } as? Constructor + if (constructor != null) { + return constructor.newInstance() + } + + if (this.enclosingClass != null) { + val enclosingObject = this.enclosingClass.newDefaultInstance() + return this.getDeclaredConstructor(this.enclosingClass) + .also { it.isAccessible = true } + .newInstance(enclosingObject) + } + + throw IllegalStateException("No suitable constructor found for ${this.canonicalName}") +} \ No newline at end of file diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/runner/ParallelThreadsRunner.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/runner/ParallelThreadsRunner.kt index acf05a799..3f49e0269 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/runner/ParallelThreadsRunner.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/runner/ParallelThreadsRunner.kt @@ -180,8 +180,7 @@ internal open class ParallelThreadsRunner( private var ensuredTestInstanceIsTransformed = false private fun createTestInstance() { - @Suppress("DEPRECATION") - testInstance = testClass.newInstance() + testInstance = testClass.newDefaultInstance() if (strategy is ModelCheckingStrategy) { // In the model checking mode, we need to ensure // that all the necessary classes and instrumented diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/verifier/LTS.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/verifier/LTS.kt index 2f8974513..74189e0e6 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/verifier/LTS.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/verifier/LTS.kt @@ -261,8 +261,7 @@ class LTS(private val sequentialSpecification: Class<*>) { } private fun createInitialStateInstance(): Any { - @Suppress("DEPRECATION") - return sequentialSpecification.newInstance().also { + return sequentialSpecification.newDefaultInstance().also { // the sequential version of the data structure used for verification // may differ from the original parallel version, // in this case we need to ensure that the sequential class is also instrumented diff --git a/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/runner/InnerClassTest.kt b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/runner/InnerClassTest.kt new file mode 100644 index 000000000..2ca17fb73 --- /dev/null +++ b/src/jvm/test/org/jetbrains/kotlinx/lincheck_test/runner/InnerClassTest.kt @@ -0,0 +1,46 @@ +/* + * Lincheck + * + * Copyright (C) 2019 - 2025 JetBrains s.r.o. + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.jetbrains.kotlinx.lincheck_test.runner + +import org.jetbrains.kotlinx.lincheck.annotations.Operation +import org.jetbrains.kotlinx.lincheck.check +import org.jetbrains.kotlinx.lincheck.strategy.stress.StressOptions +import org.junit.Test + +class OuterClass { + inner class InnerClass { + @Operation + fun zero() = 0 + } + + class NestedClass { + @Operation + fun zero() = 0 + } +} + +class InnerClassTest { + @Test + fun testInnerClass() { + StressOptions() + .invocationsPerIteration(1) + .iterations(1) + .check(OuterClass.InnerClass::class) + } + + @Test + fun testNestedClass() { + StressOptions() + .invocationsPerIteration(1) + .iterations(1) + .check(OuterClass.NestedClass::class) + } +}