[atomicfu-plugin] Added a FIR checker for property visibility
Merge-request: KT-MR-17641
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
index e4bed43..58b5ebc 100644
--- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
+++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
@@ -44,13 +44,13 @@
import org.jetbrains.kotlin.scripting.test.AbstractScriptWithCustomDefBlackBoxCodegenTest
import org.jetbrains.kotlin.scripting.test.AbstractScriptWithCustomDefDiagnosticsTestBase
import org.jetbrains.kotlin.test.TargetBackend
-import org.jetbrains.kotlinx.atomicfu.AbstractAtomicfuJsFirTest
-import org.jetbrains.kotlinx.atomicfu.AbstractAtomicfuJsIrTest
-import org.jetbrains.kotlinx.atomicfu.AbstractAtomicfuJvmFirLightTreeTest
-import org.jetbrains.kotlinx.atomicfu.AbstractAtomicfuJvmIrTest
+import org.jetbrains.kotlinx.atomicfu.runners.AbstractAtomicfuFirCheckerTest
+import org.jetbrains.kotlinx.atomicfu.runners.AbstractAtomicfuJsFirTest
+import org.jetbrains.kotlinx.atomicfu.runners.AbstractAtomicfuJsIrTest
+import org.jetbrains.kotlinx.atomicfu.runners.AbstractAtomicfuJvmFirLightTreeTest
+import org.jetbrains.kotlinx.atomicfu.runners.AbstractAtomicfuJvmIrTest
import org.jetbrains.kotlinx.atomicfu.incremental.AbstractIncrementalK2JVMWithAtomicfuRunnerTest
-
private class ExcludePattern {
companion object {
private const val MEMBER_ALIAS = "(^removeMemberTypeAlias)|(^addMemberTypeAlias)"
@@ -272,7 +272,7 @@
}
testGroup(
- "plugins/atomicfu/atomicfu-compiler/test",
+ "plugins/atomicfu/atomicfu-compiler/tests-gen",
"plugins/atomicfu/atomicfu-compiler/testData",
testRunnerMethodName = "runTest0"
) {
@@ -286,10 +286,14 @@
}
testGroup(
- "plugins/atomicfu/atomicfu-compiler/test",
+ "plugins/atomicfu/atomicfu-compiler/tests-gen",
"plugins/atomicfu/atomicfu-compiler/testData",
testRunnerMethodName = "runTest0"
) {
+ testClass<AbstractAtomicfuFirCheckerTest> {
+ model("diagnostics/")
+ }
+
testClass<AbstractAtomicfuJvmIrTest> {
model("box/")
}
diff --git a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
index ad54765..81394b7 100644
--- a/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
+++ b/plugins/atomicfu/atomicfu-compiler/build.gradle.kts
@@ -59,6 +59,14 @@
compileOnly(intellijCore())
compileOnly(libs.intellij.asm)
+ compileOnly(project(":compiler:fir:cones"))
+ compileOnly(project(":compiler:fir:tree"))
+ compileOnly(project(":compiler:fir:resolve"))
+ compileOnly(project(":compiler:fir:plugin-utils"))
+ compileOnly(project(":compiler:fir:checkers"))
+ compileOnly(project(":compiler:fir:fir2ir"))
+ compileOnly(project(":compiler:fir:entrypoint"))
+
compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:cli-common"))
compileOnly(project(":compiler:frontend"))
@@ -157,9 +165,14 @@
optInToExperimentalCompilerApi()
optInToUnsafeDuringIrConstructionAPI()
+val generationRoot = projectDir.resolve("tests-gen")
+
sourceSets {
"main" { projectDefault() }
- "test" { projectDefault() }
+ "test" {
+ projectDefault()
+ this.java.srcDir(generationRoot.name)
+ }
}
testsJar()
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt
index 419eb8c..6972c76 100644
--- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/common/AbstractAtomicfuTransformer.kt
@@ -29,43 +29,11 @@
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
+import org.jetbrains.kotlinx.atomicfu.compiler.diagnostic.AtomicfuErrorMessages.CONSTRAINTS_MESSAGE
abstract class AbstractAtomicfuTransformer(val pluginContext: IrPluginContext) {
companion object {
- const val CONSTRAINTS_MESSAGE =
- "\nPlease make sure that you follow these constraints for using atomic properties:\n" +
- " * To ensure that atomic properties are not accessed out of the current Kotlin module, it is necessary to declare atomic properties as private or internal.\n" +
- " Alternatively, you can make the containing class private or internal.\n" +
- " If you need to expose the atomic property value to the public, consider using a delegated property declared within the same scope:\n" +
- " ```\n" +
- " private val _a = atomic<T>(initial) \n" +
- " public var a: T by _a \n" +
- " ```\n" +
- " * Directly invoke operations on atomic properties, like this:\n" +
- " ```\n" +
- " val top = atomic<Node?>(null)\n" +
- " top.compareAndSet(null, Node(1)) // OK\n" +
- " ```\n" +
- " * Refrain from invoking atomic operations on local variables:\n" +
- " ```\n" +
- " val top = atomic<Node?>(null)\n" +
- " val tmp = top\n" +
- " tmp.compareAndSet(null, Node(1)) // DON'T DO THIS\n" +
- " ```\n" +
- " * Avoid leaking references to atomic values in other ways, such as returning them or passing them as parameters.\n" +
- " * Be cautious with the complexity of data flow within parameters of atomic operations.\n" +
- " For instance, instead of using intricate expression directly as an argument, e.g.:\n" +
- " ```\n" +
- " top.compareAndSet(cur, <complex_expression>)\n" +
- " ```\n" +
- " create a separate variable to hold the complex expression's value and then perform the operation:\n" +
- " ```\n" +
- " val newValue = <complex_expression>\n" +
- " top.compareAndSet(cur, newValue) \n" +
- " ```\n" +
- "\n"
-
internal const val VOLATILE = "\$volatile"
internal const val ATOMICFU = "atomicfu"
internal const val ARRAY = "array"
@@ -158,8 +126,6 @@
val isTopLevel = parentContainer is IrFile || (parentContainer is IrClass && parentContainer.kind == ClassKind.OBJECT)
when {
atomicProperty.isAtomic() -> {
- atomicProperty.checkIsFinal(isArray = false)
- atomicProperty.checkVisibility(isArray = false)
if (isTopLevel) {
parentContainer.addTransformedStaticAtomic(atomicProperty, index)
} else {
@@ -169,8 +135,6 @@
}
}
atomicProperty.isAtomicArray() -> {
- atomicProperty.checkIsFinal(isArray = true)
- atomicProperty.checkVisibility(isArray = true)
parentContainer.addTransformedAtomicArray(atomicProperty, index).also {
declarationsToBeRemoved.add(atomicProperty)
}
@@ -452,32 +416,6 @@
)
}
- private fun IrProperty.checkIsFinal(isArray: Boolean) =
- check(!isVar) {
- "Please consider declaring [${this.atomicfuRender()}] from [${this.parent.render()}] as a private val or internal val.\n" +
- if (!isArray) "If you need to declare a variable with accessors delegated to the atomic property value, you can use a delegated property declared within the same scope, e.g:\n" +
- "```\n" +
- "private val _a = atomic<T>(initial) \n" +
- "public var a: T by _a \n" +
- "```\n" else ""
- }
-
- private fun IrProperty.checkVisibility(isArray: Boolean) =
- check(
- (visibility == DescriptorVisibilities.PRIVATE || visibility == DescriptorVisibilities.INTERNAL) ||
- (parent is IrClass &&
- (parentAsClass.visibility == DescriptorVisibilities.PRIVATE || parentAsClass.visibility == DescriptorVisibilities.INTERNAL))
- ) {
- "To ensure that atomic properties are not accessed out of the current Kotlin module, it is necessary to declare atomic properties as private or internal.\n" +
- "Please consider declaring [${this.atomicfuRender()}] from [${this.parent.render()}] as a private or internal property.\n" +
- (if (parent is IrClass) "You may also make the containing class [${parentAsClass.render()}] private or internal.\n" else "") +
- if (!isArray) "Alternatively, if you need to expose the atomic property value to the public, you can use a delegated property declared within the same scope, e.g:\n" +
- "```\n" +
- "private val _a = atomic<T>(initial) \n" +
- "public var a: T by _a \n" +
- "```\n" else ""
- }
-
protected fun IrProperty.getMinVisibility(): DescriptorVisibility {
// To protect atomic properties from leaking out of the current sourceSet, they are required to be internal or private,
// or the containing class may be internal or private.
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt
index 6f4cfce..0dea857 100644
--- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/jvm/AtomicfuJvmIrTransformer.kt
@@ -19,6 +19,8 @@
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuIrBuilder
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuTransformer
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuTransformer.Companion.ATOMICFU
+import org.jetbrains.kotlinx.atomicfu.compiler.diagnostic.AtomicfuErrorMessages.CONSTRAINTS_MESSAGE
+
import kotlin.collections.set
private const val DISPATCH_RECEIVER = "dispatchReceiver\$$ATOMICFU"
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/native/AtomicfuNativeIrTransformer.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/native/AtomicfuNativeIrTransformer.kt
index c1f8c61..d71a0c5 100644
--- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/native/AtomicfuNativeIrTransformer.kt
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/backend/native/AtomicfuNativeIrTransformer.kt
@@ -24,6 +24,7 @@
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuIrBuilder
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuTransformer
import org.jetbrains.kotlinx.atomicfu.compiler.backend.common.AbstractAtomicfuTransformer.Companion.ATOMICFU
+import org.jetbrains.kotlinx.atomicfu.compiler.diagnostic.AtomicfuErrorMessages.CONSTRAINTS_MESSAGE
private const val REF_GETTER = "refGetter\$$ATOMICFU"
private const val ATOMIC_ARRAY = "atomicArray\$$ATOMICFU"
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrorMessages.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrorMessages.kt
new file mode 100644
index 0000000..9dd56a7
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrorMessages.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.compiler.diagnostic
+
+import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
+import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
+import org.jetbrains.kotlin.diagnostics.rendering.Renderers
+
+object AtomicfuErrorMessages : BaseDiagnosticRendererFactory() {
+
+ const val CONSTRAINTS_MESSAGE =
+ "\nPlease make sure that you follow these constraints for using atomic properties:\n" +
+ " * To ensure that atomic properties are not accessed out of the current Kotlin module, it is necessary to declare atomic properties as private or internal.\n" +
+ " Alternatively, you can make the containing class private or internal.\n" +
+ " If you need to expose the atomic property value to the public, consider using a delegated property declared within the same scope:\n" +
+ " ```\n" +
+ " private val _a = atomic<T>(initial) \n" +
+ " public var a: T by _a \n" +
+ " ```\n" +
+ " * Directly invoke operations on atomic properties, like this:\n" +
+ " ```\n" +
+ " val top = atomic<Node?>(null)\n" +
+ " top.compareAndSet(null, Node(1)) // OK\n" +
+ " ```\n" +
+ " * Refrain from invoking atomic operations on local variables:\n" +
+ " ```\n" +
+ " val top = atomic<Node?>(null)\n" +
+ " val tmp = top\n" +
+ " tmp.compareAndSet(null, Node(1)) // DON'T DO THIS\n" +
+ " ```\n" +
+ " * Avoid leaking references to atomic values in other ways, such as returning them or passing them as parameters.\n" +
+ " * Be cautious with the complexity of data flow within parameters of atomic operations.\n" +
+ " For instance, instead of using intricate expression directly as an argument, e.g.:\n" +
+ " ```\n" +
+ " top.compareAndSet(cur, <complex_expression>)\n" +
+ " ```\n" +
+ " create a separate variable to hold the complex expression's value and then perform the operation:\n" +
+ " ```\n" +
+ " val newValue = <complex_expression>\n" +
+ " top.compareAndSet(cur, newValue) \n" +
+ " ```\n" +
+ "\n"
+
+ private const val PUBLIC_ATOMICS_ARE_FORBIDDEN_MESSAGE =
+ "\nTo prevent atomic properties from being referenced outside the current Kotlin module, they should be declared as either private or internal. " +
+ "Note, that `@kotlin.PublishedApi` annotation, when applied to a class or a member with internal visibility, makes it effectively public.\n" +
+ "Please consider setting the visibility of the property `''{0}''` to private or internal or limit the scope of the containing class. \n" +
+ "Alternatively, if you need to expose the atomic property value to the public, you can use a delegated property declared within the same scope, e.g:\n" +
+ "```\n" +
+ "private val _a = atomic<T>(initial) \n" +
+ "public val a: T by _a \n" +
+ "```\n"
+
+ private const val ATOMIC_PROEPRTIES_SHOULD_BE_VAL_MESSAGE = "Please consider declaring `''{0}''` as a private val or internal val.\n" +
+ "If you need to declare a variable with accessors delegated to the atomic property value, you can use a delegated property declared within the same scope, e.g:\n" +
+ "```\n" +
+ "private val _a = atomic<T>(initial) \n" +
+ "public var a: T by _a \n" +
+ "```\n"
+
+ override val MAP: KtDiagnosticFactoryToRendererMap = KtDiagnosticFactoryToRendererMap("Atomicfu Plugin").also { map ->
+ map.put(
+ AtomicfuErrors.PUBLIC_ATOMICS_ARE_FORBIDDEN, PUBLIC_ATOMICS_ARE_FORBIDDEN_MESSAGE, Renderers.TO_STRING
+ )
+ map.put(
+ AtomicfuErrors.PUBLISHED_API_ATOMICS_ARE_FORBIDDEN, PUBLIC_ATOMICS_ARE_FORBIDDEN_MESSAGE, Renderers.TO_STRING
+ )
+ map.put(
+ AtomicfuErrors.ATOMIC_PROPERTIES_SHOULD_BE_VAL, ATOMIC_PROEPRTIES_SHOULD_BE_VAL_MESSAGE, Renderers.TO_STRING
+ )
+ }
+
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrors.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrors.kt
new file mode 100644
index 0000000..a2c2fe2
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuErrors.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.compiler.diagnostic
+
+import org.jetbrains.kotlin.diagnostics.*
+import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
+import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
+import org.jetbrains.kotlin.psi.KtProperty
+
+object AtomicfuErrors {
+ val PUBLIC_ATOMICS_ARE_FORBIDDEN = KtDiagnosticFactory1<String>("PUBLIC_ATOMICS_ARE_FORBIDDEN",
+ Severity.ERROR, SourceElementPositioningStrategies.VISIBILITY_MODIFIER, KtProperty::class)
+
+ // This diagnostic should be upgraded to error in the next release: KT-70982
+ val PUBLISHED_API_ATOMICS_ARE_FORBIDDEN = KtDiagnosticFactory1<String>("PUBLISHED_API_ATOMICS_ARE_FORBIDDEN",
+ Severity.WARNING, SourceElementPositioningStrategies.VISIBILITY_MODIFIER, KtProperty::class)
+
+ val ATOMIC_PROPERTIES_SHOULD_BE_VAL = KtDiagnosticFactory1<String>("ATOMIC_PROPERTIES_SHOULD_BE_VAL",
+ Severity.ERROR, SourceElementPositioningStrategies.VAL_OR_VAR_NODE, KtProperty::class)
+
+ init {
+ RootDiagnosticRendererFactory.registerFactory(AtomicfuErrorMessages)
+ }
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuPropertyChecker.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuPropertyChecker.kt
new file mode 100644
index 0000000..b0d6de1
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/diagnostic/AtomicfuPropertyChecker.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.compiler.diagnostic
+
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
+import org.jetbrains.kotlin.fir.declarations.FirProperty
+import org.jetbrains.kotlin.fir.declarations.utils.visibility
+import org.jetbrains.kotlin.fir.expressions.FirAnnotation
+import org.jetbrains.kotlin.fir.resolve.toClassLikeSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
+import org.jetbrains.kotlin.fir.types.classId
+import org.jetbrains.kotlin.fir.types.coneType
+import org.jetbrains.kotlin.text
+
+private const val KOTLINX_ATOMICFU = "kotlinx.atomicfu"
+private const val PUBLISHED_API = "kotlin.PublishedApi"
+
+private fun FirProperty.isKotlinxAtomicfu(): Boolean = returnTypeRef.coneType.classId?.packageFqName?.asString() == KOTLINX_ATOMICFU
+
+private fun FirProperty.isPublishedApi(): Boolean = annotations.any(::isMarkedWithPublishedApi)
+
+private fun FirClassLikeSymbol<*>.isPublishedApi(): Boolean = annotations.any(::isMarkedWithPublishedApi)
+private fun FirClassLikeSymbol<*>.isPublic(): Boolean = resolvedStatus.visibility.isPublicAPI
+
+private fun isMarkedWithPublishedApi(a: FirAnnotation): Boolean =
+ a.annotationTypeRef.coneType.classId?.asFqNameString() == PUBLISHED_API
+
+object AtomicfuPropertyChecker: FirPropertyChecker(MppCheckerKind.Common) {
+ override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
+ if (!declaration.isKotlinxAtomicfu()) return
+ val containingClassSymbol = declaration.dispatchReceiverType?.toClassLikeSymbol(context.session)
+ if (declaration.visibility.isPublicAPI &&
+ (containingClassSymbol == null || containingClassSymbol.isPublic())) {
+ reporter.reportOn(
+ declaration.source,
+ AtomicfuErrors.PUBLIC_ATOMICS_ARE_FORBIDDEN,
+ declaration.source.text.toString(),
+ context
+ )
+ } else {
+ if ((declaration.visibility.isPublicAPI || declaration.isPublishedApi()) &&
+ (containingClassSymbol == null || containingClassSymbol.isPublic() || containingClassSymbol.isPublishedApi())) {
+ reporter.reportOn(
+ declaration.source,
+ AtomicfuErrors.PUBLISHED_API_ATOMICS_ARE_FORBIDDEN,
+ declaration.source.text.toString(),
+ context
+ )
+ }
+ }
+ if (declaration.isVar) {
+ reporter.reportOn(
+ declaration.source,
+ AtomicfuErrors.ATOMIC_PROPERTIES_SHOULD_BE_VAL,
+ declaration.source.text.toString(),
+ context
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuComponentRegistrar.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuComponentRegistrar.kt
index 355b601..76aecd3 100644
--- a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuComponentRegistrar.kt
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuComponentRegistrar.kt
@@ -19,10 +19,13 @@
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
+import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
+import org.jetbrains.kotlinx.atomicfu.compiler.diagnostic.AtomicfuFirDeclarationCheckers
class AtomicfuComponentRegistrar : CompilerPluginRegistrar() {
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
- Companion.registerExtensions(this)
+ registerExtensions(this)
}
override val supportsK2: Boolean
@@ -30,7 +33,14 @@
companion object {
fun registerExtensions(extensionStorage: ExtensionStorage) = with(extensionStorage) {
+ FirExtensionRegistrarAdapter.registerExtension(AtomicfuFirExtensionRegistrar())
IrGenerationExtension.registerExtension(AtomicfuLoweringExtension())
}
}
}
+
+class AtomicfuFirExtensionRegistrar : FirExtensionRegistrar() {
+ override fun ExtensionRegistrarContext.configurePlugin() {
+ +::AtomicfuFirDeclarationCheckers
+ }
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuFirDeclarationCheckers.kt b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuFirDeclarationCheckers.kt
new file mode 100644
index 0000000..95af767
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/src/org/jetbrains/kotlinx/atomicfu/compiler/extensions/AtomicfuFirDeclarationCheckers.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.compiler.diagnostic
+
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
+import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
+import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
+
+class AtomicfuFirDeclarationCheckers(session: FirSession) : FirAdditionalCheckersExtension(session) {
+ override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
+ override val propertyCheckers: Set<FirPropertyChecker>
+ get() = setOf(AtomicfuPropertyChecker)
+ }
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJvmIrTest.kt b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJvmIrTest.kt
deleted file mode 100644
index 72de0b5..0000000
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJvmIrTest.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlinx.atomicfu
-
-import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
-import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar.ExtensionStorage
-import org.jetbrains.kotlin.config.CompilerConfiguration
-import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
-import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
-import org.jetbrains.kotlin.test.model.TestModule
-import org.jetbrains.kotlin.test.runners.codegen.AbstractFirLightTreeBlackBoxCodegenTest
-import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest
-import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
-import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
-import org.jetbrains.kotlin.utils.PathUtil
-import org.jetbrains.kotlinx.atomicfu.compiler.extensions.AtomicfuComponentRegistrar
-import java.io.File
-
-private val librariesPaths = getLibrariesPaths()
-
-open class AbstractAtomicfuJvmIrTest : AbstractIrBlackBoxCodegenTest() {
- override fun configure(builder: TestConfigurationBuilder) {
- super.configure(builder)
- builder.configureForKotlinxAtomicfu(librariesPaths)
- }
-}
-
-open class AbstractAtomicfuJvmFirLightTreeTest : AbstractFirLightTreeBlackBoxCodegenTest() {
- override fun configure(builder: TestConfigurationBuilder) {
- super.configure(builder)
- builder.configureForKotlinxAtomicfu(librariesPaths)
- }
-}
-
-private fun getLibraryJar(classToDetect: String): File? = try {
- PathUtil.getResourcePathForClass(Class.forName(classToDetect))
-} catch (e: ClassNotFoundException) {
- null
-}
-
-private fun getLibrariesPaths(): List<File> {
- val coreLibraryPath = getLibraryJar("kotlinx.atomicfu.AtomicFU") ?: error("kotlinx.atomicfu library is not found")
- val kotlinTestPath = getLibraryJar("kotlin.test.AssertionsKt") ?: error("kotlin.test is not found")
- val kotlinJvm = getLibraryJar("kotlin.jvm.JvmField") ?: error("kotlin-stdlib is not found")
- return listOf(coreLibraryPath, kotlinTestPath, kotlinJvm)
-}
-
-private fun TestConfigurationBuilder.configureForKotlinxAtomicfu(librariesPaths: List<File>) {
- useConfigurators(
- { services ->
- object : EnvironmentConfigurator(services) {
- override fun configureCompilerConfiguration(
- configuration: CompilerConfiguration,
- module: TestModule
- ) {
- configuration.addJvmClasspathRoots(librariesPaths)
- }
-
- override fun ExtensionStorage.registerCompilerExtensions(module: TestModule, configuration: CompilerConfiguration) {
- AtomicfuComponentRegistrar.registerExtensions(this)
- }
- }
- })
-
- useCustomRuntimeClasspathProviders(
- {
- object : RuntimeClasspathProvider(it) {
- override fun runtimeClassPaths(module: TestModule): List<File> = librariesPaths
- }
- }
- )
-
- defaultDirectives {
- +CodegenTestDirectives.CHECK_BYTECODE_LISTING
- }
-}
-
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJsIrTest.kt b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuJsIrTest.kt
similarity index 98%
rename from plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJsIrTest.kt
rename to plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuJsIrTest.kt
index 269ce9c..7f71594 100644
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AbstractAtomicfuJsIrTest.kt
+++ b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuJsIrTest.kt
@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package org.jetbrains.kotlinx.atomicfu
+package org.jetbrains.kotlinx.atomicfu.runners
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuPluginTestRunners.kt b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuPluginTestRunners.kt
new file mode 100644
index 0000000..3c1404b
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AbstractAtomicfuPluginTestRunners.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.runners
+
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.frontend.fir.FirFailingTestSuppressor
+import org.jetbrains.kotlin.test.runners.AbstractFirPsiDiagnosticTest
+import org.jetbrains.kotlin.test.runners.codegen.*
+
+open class AbstractAtomicfuJvmIrTest : AbstractIrBlackBoxCodegenTest() {
+ override fun configure(builder: TestConfigurationBuilder) {
+ super.configure(builder)
+ builder.configureForKotlinxAtomicfu()
+ }
+}
+
+open class AbstractAtomicfuJvmFirLightTreeTest : AbstractFirLightTreeBlackBoxCodegenTest() {
+ override fun configure(builder: TestConfigurationBuilder) {
+ super.configure(builder)
+ builder.configureForKotlinxAtomicfu()
+ }
+}
+
+abstract class AbstractAtomicfuFirCheckerTest : AbstractFirPsiDiagnosticTest() {
+ override fun configure(builder: TestConfigurationBuilder) {
+ super.configure(builder)
+ with(builder) {
+ configureForKotlinxAtomicfu()
+ useAfterAnalysisCheckers(::FirFailingTestSuppressor)
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuExtensionRegistrarConfigurator.kt b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuExtensionRegistrarConfigurator.kt
new file mode 100644
index 0000000..952b65321
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuExtensionRegistrarConfigurator.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.runners
+
+import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
+import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
+import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar.ExtensionStorage
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
+import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
+import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
+import org.jetbrains.kotlin.test.services.RuntimeClasspathProvider
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlin.utils.PathUtil
+import org.jetbrains.kotlinx.atomicfu.compiler.extensions.AtomicfuFirExtensionRegistrar
+import org.jetbrains.kotlinx.atomicfu.compiler.extensions.AtomicfuLoweringExtension
+import java.io.File
+
+internal fun TestConfigurationBuilder.configureForKotlinxAtomicfu() {
+ useConfigurators(
+ ::AtomicfuExtensionRegistrarConfigurator
+ )
+
+ useCustomRuntimeClasspathProviders(
+ {
+ object : RuntimeClasspathProvider(it) {
+ override fun runtimeClassPaths(module: TestModule): List<File> = getLibrariesPaths()
+ }
+ }
+ )
+
+ defaultDirectives {
+ +CodegenTestDirectives.CHECK_BYTECODE_LISTING
+ }
+}
+
+class AtomicfuExtensionRegistrarConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
+ override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
+ configuration.addJvmClasspathRoots(getLibrariesPaths())
+ }
+
+ override fun ExtensionStorage.registerCompilerExtensions(module: TestModule, configuration: CompilerConfiguration) {
+ FirExtensionRegistrarAdapter.registerExtension(AtomicfuFirExtensionRegistrar())
+ IrGenerationExtension.registerExtension(AtomicfuLoweringExtension())
+ }
+}
+
+private fun getLibraryJar(classToDetect: String): File? = try {
+ PathUtil.getResourcePathForClass(Class.forName(classToDetect))
+} catch (e: ClassNotFoundException) {
+ null
+}
+
+private fun getLibrariesPaths(): List<File> {
+ val coreLibraryPath = getLibraryJar("kotlinx.atomicfu.AtomicFU") ?: error("kotlinx.atomicfu library is not found")
+ val kotlinTestPath = getLibraryJar("kotlin.test.AssertionsKt") ?: error("kotlin.test is not found")
+ val kotlinJvm = getLibraryJar("kotlin.jvm.JvmField") ?: error("kotlin-stdlib is not found")
+ return listOf(coreLibraryPath, kotlinTestPath, kotlinJvm)
+}
+
diff --git a/plugins/atomicfu/atomicfu-compiler/testData/diagnostics/CheckAtomicVisibilityTest.kt b/plugins/atomicfu/atomicfu-compiler/testData/diagnostics/CheckAtomicVisibilityTest.kt
new file mode 100644
index 0000000..e5cf12f
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/testData/diagnostics/CheckAtomicVisibilityTest.kt
@@ -0,0 +1,53 @@
+import kotlinx.atomicfu.*
+import kotlin.test.*
+
+class A {
+ <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>public<!> val a = atomic(true)
+ @PublishedApi <!PUBLISHED_API_ATOMICS_ARE_FORBIDDEN!>internal<!> val b = atomic(false)
+ <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>public<!> <!ATOMIC_PROPERTIES_SHOULD_BE_VAL!>var<!> c = atomic(false)
+ internal val d = atomic(0)
+
+ public inline fun update(newValue: Boolean, lambda: (Boolean) -> Unit) {
+ val oldValue = b.getAndSet(newValue)
+ lambda(oldValue)
+ }
+}
+
+@PublishedApi
+internal class A1 {
+ val <!PUBLISHED_API_ATOMICS_ARE_FORBIDDEN!>a<!> = atomic(0)
+ @PublishedApi <!PUBLISHED_API_ATOMICS_ARE_FORBIDDEN!>internal<!> val b = atomic(false)
+ internal val c = atomic(0)
+}
+
+internal class A2 {
+ val a = atomic(0)
+ @PublishedApi internal val b = atomic(0)
+ internal val c = atomic(0)
+}
+
+private class A3 {
+ val a = atomic(0)
+ @PublishedApi internal val b = atomic(0)
+ internal val c = atomic(0)
+}
+
+abstract class Base {
+ val <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>a<!> = atomic(0)
+ @PublishedApi <!PUBLISHED_API_ATOMICS_ARE_FORBIDDEN!>internal<!> val b = atomic(0)
+ internal val c = atomic(0)
+ <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>protected<!> val d = atomic(0)
+
+ protected class Nested {
+ val <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>nestedA<!> = atomic(0)
+ @PublishedApi <!PUBLISHED_API_ATOMICS_ARE_FORBIDDEN!>internal<!> val nestedB = atomic(0)
+ internal val nestedC = atomic(0)
+ <!PUBLIC_ATOMICS_ARE_FORBIDDEN!>protected<!> val nestedD = atomic(0)
+ }
+}
+
+fun box(): String {
+ val aClass = A()
+ aClass.update(true) { i -> assertFalse(i) }
+ return "OK"
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuFirCheckerTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuFirCheckerTestGenerated.java
new file mode 100644
index 0000000..b4c870d
--- /dev/null
+++ b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuFirCheckerTestGenerated.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlinx.atomicfu.runners;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.jetbrains.kotlin.test.TargetBackend;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateTestsKt}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("plugins/atomicfu/atomicfu-compiler/testData/diagnostics")
+@TestDataPath("$PROJECT_ROOT")
+public class AtomicfuFirCheckerTestGenerated extends AbstractAtomicfuFirCheckerTest {
+ @Test
+ public void testAllFilesPresentInDiagnostics() {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/atomicfu/atomicfu-compiler/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("CheckAtomicVisibilityTest.kt")
+ public void testCheckAtomicVisibilityTest() {
+ runTest("plugins/atomicfu/atomicfu-compiler/testData/diagnostics/CheckAtomicVisibilityTest.kt");
+ }
+}
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsFirTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsFirTestGenerated.java
similarity index 99%
rename from plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsFirTestGenerated.java
rename to plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsFirTestGenerated.java
index 5ab65cc..3417b98 100644
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsFirTestGenerated.java
+++ b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsFirTestGenerated.java
@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package org.jetbrains.kotlinx.atomicfu;
+package org.jetbrains.kotlinx.atomicfu.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsIrTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsIrTestGenerated.java
similarity index 99%
rename from plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsIrTestGenerated.java
rename to plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsIrTestGenerated.java
index cdcfb6b..6f176dd 100644
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJsIrTestGenerated.java
+++ b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJsIrTestGenerated.java
@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package org.jetbrains.kotlinx.atomicfu;
+package org.jetbrains.kotlinx.atomicfu.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmFirLightTreeTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmFirLightTreeTestGenerated.java
similarity index 99%
rename from plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmFirLightTreeTestGenerated.java
rename to plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmFirLightTreeTestGenerated.java
index 8faaf0a..2120205 100644
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmFirLightTreeTestGenerated.java
+++ b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmFirLightTreeTestGenerated.java
@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package org.jetbrains.kotlinx.atomicfu;
+package org.jetbrains.kotlinx.atomicfu.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
diff --git a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmIrTestGenerated.java b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmIrTestGenerated.java
similarity index 99%
rename from plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmIrTestGenerated.java
rename to plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmIrTestGenerated.java
index f7dea97..6d8332d 100644
--- a/plugins/atomicfu/atomicfu-compiler/test/org/jetbrains/kotlinx/atomicfu/AtomicfuJvmIrTestGenerated.java
+++ b/plugins/atomicfu/atomicfu-compiler/tests-gen/org/jetbrains/kotlinx/atomicfu/runners/AtomicfuJvmIrTestGenerated.java
@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
-package org.jetbrains.kotlinx.atomicfu;
+package org.jetbrains.kotlinx.atomicfu.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;