From 24e07fdfe05fcbfa6a91c6c6cf319a2199939efe Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 31 May 2023 16:19:28 +0300 Subject: [PATCH] [FIR plugin] Add test for plugin which generates annotations on IR ^KT-58638 --- .../kotlin/generators/tests/GenerateTests.kt | 5 + plugins/fir-plugin-prototype/build.gradle.kts | 1 + .../kotlin/fir/plugin/annotations.kt | 4 + .../GeneratedDeclarationsIrBodyFiller.kt | 3 +- .../plugin/TransformerForAddingAnnotations.kt | 73 +++++++++++++++ ...notationsGeneratedInBackend.fir.k2.jvm.txt | 14 +++ ...otationsGeneratedInBackend.fir.k2.klib.txt | 14 +++ .../annotationsGeneratedInBackend.fir.kt.txt | 35 +++++++ .../annotationsGeneratedInBackend.kt | 12 +++ ...mpiledWithPluginJsKotlinTestGenerated.java | 45 +++++++++ ...piledWithPluginJvmKotlinTestGenerated.java | 6 ++ .../plugin/runners/PluginPrototypeTests.kt | 21 +++++ .../services/PluginAnnotationsProvider.kt | 92 ++++++++++++++----- 13 files changed, 300 insertions(+), 25 deletions(-) create mode 100644 plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt create mode 100644 plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.jvm.txt create mode 100644 plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt create mode 100644 plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.kt.txt create mode 100644 plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt create mode 100644 plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJsKotlinTestGenerated.java diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 3ce573fa6b1..809f4c90188 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.assignment.plugin.AbstractFirLightTreeBlackBoxCodege import org.jetbrains.kotlin.assignment.plugin.AbstractFirPsiAssignmentPluginDiagnosticTest import org.jetbrains.kotlin.assignment.plugin.AbstractIrBlackBoxCodegenTestAssignmentPlugin import org.jetbrains.kotlin.fir.plugin.runners.AbstractFirLightTreePluginBlackBoxCodegenTest +import org.jetbrains.kotlin.fir.plugin.runners.AbstractFirLoadK2CompiledWithPluginJsKotlinTest import org.jetbrains.kotlin.fir.plugin.runners.AbstractFirLoadK2CompiledWithPluginJvmKotlinTest import org.jetbrains.kotlin.fir.plugin.runners.AbstractFirPsiPluginDiagnosticTest import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5 @@ -265,6 +266,10 @@ fun main(args: Array) { testClass { model("firLoadK2Compiled") } + + testClass { + model("firLoadK2Compiled") + } } testGroup( diff --git a/plugins/fir-plugin-prototype/build.gradle.kts b/plugins/fir-plugin-prototype/build.gradle.kts index 02ee15f0481..7c8b8b87710 100644 --- a/plugins/fir-plugin-prototype/build.gradle.kts +++ b/plugins/fir-plugin-prototype/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { testApi(projectTests(":compiler:test-infrastructure")) testApi(projectTests(":compiler:test-infrastructure-utils")) testApi(projectTests(":compiler:fir:analysis-tests")) + testApi(projectTests(":js:js.tests")) testApi(project(":compiler:fir:checkers")) testApi(project(":compiler:fir:checkers:checkers.jvm")) testApi(project(":compiler:fir:checkers:checkers.js")) diff --git a/plugins/fir-plugin-prototype/plugin-annotations/src/commonMain/kotlin/org/jetbrains/kotlin/fir/plugin/annotations.kt b/plugins/fir-plugin-prototype/plugin-annotations/src/commonMain/kotlin/org/jetbrains/kotlin/fir/plugin/annotations.kt index 7688463494a..76d25bf8446 100644 --- a/plugins/fir-plugin-prototype/plugin-annotations/src/commonMain/kotlin/org/jetbrains/kotlin/fir/plugin/annotations.kt +++ b/plugins/fir-plugin-prototype/plugin-annotations/src/commonMain/kotlin/org/jetbrains/kotlin/fir/plugin/annotations.kt @@ -39,3 +39,7 @@ annotation class MetaSupertype annotation class MyComposable annotation class AllPropertiesConstructor + +annotation class AddAnnotations + +annotation class AnnotationToAdd diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/GeneratedDeclarationsIrBodyFiller.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/GeneratedDeclarationsIrBodyFiller.kt index be27a0c2ab9..8a72274cabb 100644 --- a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/GeneratedDeclarationsIrBodyFiller.kt +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/GeneratedDeclarationsIrBodyFiller.kt @@ -17,7 +17,8 @@ class GeneratedDeclarationsIrBodyFiller : IrGenerationExtension { TransformerForCompanionGenerator(pluginContext), TransformerForAdditionalMembersGenerator(pluginContext), TransformerForTopLevelDeclarationsGenerator(pluginContext), - AllPropertiesConstructorIrGenerator(pluginContext) + AllPropertiesConstructorIrGenerator(pluginContext), + TransformerForAddingAnnotations(pluginContext), ) for (transformer in transformers) { diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt new file mode 100644 index 00000000000..945f5e0f1e8 --- /dev/null +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2023 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.kotlin.ir.plugin + +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.ir.util.isAnnotationClass +import org.jetbrains.kotlin.ir.util.isFakeOverride +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +class TransformerForAddingAnnotations(val context: IrPluginContext) : IrElementVisitorVoid { + companion object { + private val markerAnnotationFqName = FqName("org.jetbrains.kotlin.fir.plugin.AddAnnotations") + private val annotationToAddId = ClassId(FqName("org.jetbrains.kotlin.fir.plugin"), Name.identifier("AnnotationToAdd")) + private val annotationToAddFqName = annotationToAddId.asSingleFqName() + } + + private val annotationsAdder = AnnotationsAdder() + + override fun visitElement(element: IrElement) { + when (element) { + is IrFile, + is IrModuleFragment -> element.acceptChildrenVoid(this) + else -> {} + } + } + + override fun visitClass(declaration: IrClass) { + if (declaration.hasAnnotation(markerAnnotationFqName)) { + declaration.acceptVoid(annotationsAdder) + } + } + + private inner class AnnotationsAdder : IrElementVisitorVoid { + val annotationClass = context.referenceClass(annotationToAddId)?.takeIf { it.owner.isAnnotationClass } + + override fun visitElement(element: IrElement, data: Nothing?) {} + + override fun visitDeclaration(declaration: IrDeclarationBase) { + addAnnotation(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction) { + if (declaration.isFakeOverride) return + visitDeclaration(declaration) + } + + private fun addAnnotation(declaration: IrDeclarationBase) { + if (declaration.hasAnnotation(annotationToAddFqName)) return + val annotationClass = annotationClass ?: return + val annotationConstructor = annotationClass.owner.constructors.first() + val annotationCall = IrConstructorCallImpl.fromSymbolOwner( + type = annotationClass.defaultType, + constructorSymbol = annotationConstructor.symbol + ) + declaration.annotations += annotationCall + } + } +} diff --git a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.jvm.txt b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.jvm.txt new file mode 100644 index 00000000000..8be543f4685 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.jvm.txt @@ -0,0 +1,14 @@ +@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final class Some : R|kotlin/Any| { + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final fun foo(): R|kotlin/Unit| + + @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() field:@FIELD:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final val x: R|kotlin/Int| + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public get(): R|kotlin/Int| + + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public constructor(@R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() x: R|kotlin/Int|): R|test/Some| + + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final class Derived : R|kotlin/Any| { + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public constructor(): R|test/Some.Derived| + + } + +} diff --git a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt new file mode 100644 index 00000000000..88f3ff6e420 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt @@ -0,0 +1,14 @@ +@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Some : R|kotlin/Any| { + public final fun foo(): R|kotlin/Unit| + + public final val x: R|kotlin/Int| + public get(): R|kotlin/Int| + + public constructor(x: R|kotlin/Int|): R|test/Some| + + public final class Derived : R|kotlin/Any| { + public constructor(): R|test/Some.Derived| + + } + +} diff --git a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.kt.txt b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.kt.txt new file mode 100644 index 00000000000..6fb4695cadf --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.kt.txt @@ -0,0 +1,35 @@ +package test + +@AddAnnotations +@AnnotationToAdd +class Some { + @AnnotationToAdd + constructor(@AnnotationToAdd x: Int) /* primary */ { + super/*Any*/() + /* () */ + + } + + @AnnotationToAdd + val x: Int + field = x + @AnnotationToAdd + get + + @AnnotationToAdd + fun foo() { + } + + @AnnotationToAdd + class Derived { + @AnnotationToAdd + constructor() /* primary */ { + super/*Any*/() + /* () */ + + } + + } + +} + diff --git a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt new file mode 100644 index 00000000000..607ee546983 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt @@ -0,0 +1,12 @@ +// PLATFORM_DEPENDANT_METADATA +// DUMP_KT_IR +package test + +import org.jetbrains.kotlin.fir.plugin.AddAnnotations + +@AddAnnotations +class Some(val x: Int) { + fun foo() {} + + class Derived +} diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJsKotlinTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJsKotlinTestGenerated.java new file mode 100644 index 00000000000..cc68191ae28 --- /dev/null +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJsKotlinTestGenerated.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2023 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.kotlin.fir.plugin.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.Nested; +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/fir-plugin-prototype/testData/firLoadK2Compiled") +@TestDataPath("$PROJECT_ROOT") +public class FirLoadK2CompiledWithPluginJsKotlinTestGenerated extends AbstractFirLoadK2CompiledWithPluginJsKotlinTest { + @Test + public void testAllFilesPresentInFirLoadK2Compiled() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir-plugin-prototype/testData/firLoadK2Compiled"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("annotationsGeneratedInBackend.kt") + public void testAnnotationsGeneratedInBackend() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt"); + } + + @Test + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/firLoadK2Compiled/simple.kt"); + } + + @Test + @TestMetadata("simple-lang-ver-2.1.kt") + public void testSimple_lang_ver_2_1() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/firLoadK2Compiled/simple-lang-ver-2.1.kt"); + } +} diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJvmKotlinTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJvmKotlinTestGenerated.java index e3d0e410392..f60305aa318 100644 --- a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJvmKotlinTestGenerated.java +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLoadK2CompiledWithPluginJvmKotlinTestGenerated.java @@ -25,6 +25,12 @@ public class FirLoadK2CompiledWithPluginJvmKotlinTestGenerated extends AbstractF KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir-plugin-prototype/testData/firLoadK2Compiled"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("annotationsGeneratedInBackend.kt") + public void testAnnotationsGeneratedInBackend() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.kt"); + } + @Test @TestMetadata("simple.kt") public void testSimple() throws Exception { diff --git a/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/runners/PluginPrototypeTests.kt b/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/runners/PluginPrototypeTests.kt index dfc55ce84e7..9c967a7d855 100644 --- a/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/runners/PluginPrototypeTests.kt +++ b/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/runners/PluginPrototypeTests.kt @@ -7,7 +7,11 @@ package org.jetbrains.kotlin.fir.plugin.runners import org.jetbrains.kotlin.fir.plugin.services.ExtensionRegistrarConfigurator import org.jetbrains.kotlin.fir.plugin.services.PluginAnnotationsProvider +import org.jetbrains.kotlin.fir.plugin.services.PluginRuntimeAnnotationsProvider +import org.jetbrains.kotlin.js.test.fir.AbstractFirLoadK2CompiledJsKotlinTest +import org.jetbrains.kotlin.test.backend.handlers.IrPrettyKotlinDumpHandler import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.builders.configureIrHandlersStep import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.FIR_DUMP import org.jetbrains.kotlin.test.runners.AbstractFirLoadK2CompiledJvmKotlinTest @@ -30,6 +34,18 @@ abstract class AbstractFirPsiPluginDiagnosticTest : AbstractFirPsiDiagnosticTest } open class AbstractFirLoadK2CompiledWithPluginJvmKotlinTest : AbstractFirLoadK2CompiledJvmKotlinTest() { + override fun configure(builder: TestConfigurationBuilder) { + super.configure(builder) + with(builder) { + commonFirWithPluginFrontendConfiguration() + configureIrHandlersStep { + useHandlers(::IrPrettyKotlinDumpHandler) + } + } + } +} + +open class AbstractFirLoadK2CompiledWithPluginJsKotlinTest : AbstractFirLoadK2CompiledJsKotlinTest() { override fun configure(builder: TestConfigurationBuilder) { super.configure(builder) builder.commonFirWithPluginFrontendConfiguration() @@ -48,4 +64,9 @@ fun TestConfigurationBuilder.commonFirWithPluginFrontendConfiguration() { ::PluginAnnotationsProvider, ::ExtensionRegistrarConfigurator ) + + useCustomRuntimeClasspathProviders( + ::PluginRuntimeAnnotationsProvider + ) } + diff --git a/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/services/PluginAnnotationsProvider.kt b/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/services/PluginAnnotationsProvider.kt index 0b480775073..5e31b3df0d3 100644 --- a/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/services/PluginAnnotationsProvider.kt +++ b/plugins/fir-plugin-prototype/tests/org/jetbrains/kotlin/fir/plugin/services/PluginAnnotationsProvider.kt @@ -7,38 +7,82 @@ package org.jetbrains.kotlin.fir.plugin.services import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.platform.jvm.isJvm 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.test.services.assertions import java.io.File import java.io.FilenameFilter class PluginAnnotationsProvider(testServices: TestServices) : EnvironmentConfigurator(testServices) { - companion object { - private const val ANNOTATIONS_JAR_DIR = "plugins/fir-plugin-prototype/plugin-annotations/build/libs/" - private val ANNOTATIONS_JAR_FILTER = FilenameFilter { _, name -> name.startsWith("plugin-annotations") && name.endsWith(".jar") } - } - override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { - val pluginAnnotationsJar = findJarFromProperty() - ?: findJarByPath() - ?: error("Jar with annotations does not exist. Please run :plugins:fir-plugin-prototype:plugin-annotations:jar or specify firPluginAnnotations.path system property") - configuration.addJvmClasspathRoot(pluginAnnotationsJar) - } - - private fun findJarByPath(): File? { - val libDir = File(ANNOTATIONS_JAR_DIR) - if (!libDir.exists() || !libDir.isDirectory) return null - return libDir.listFiles(ANNOTATIONS_JAR_FILTER)?.firstOrNull() - } - - private fun findJarFromProperty(): File? { - val firPluginAnnotationsPath = System.getProperty("firPluginAnnotations.path") ?: return null - return File(firPluginAnnotationsPath).takeIf { - it.isFile && - it.name.startsWith("plugin-annotations") && - it.name.endsWith(".jar") + // TODO: handle property + val platform = module.targetPlatform + when { + platform.isJvm() -> { + val jar = findJvmLib() + configuration.addJvmClasspathRoot(jar) + } + platform.isJs() -> { + val jar = findJsLib() + val libraries = configuration.getList(JSConfigurationKeys.LIBRARIES) + configuration.put(JSConfigurationKeys.LIBRARIES, libraries + jar.absolutePath) + } } } } + +class PluginRuntimeAnnotationsProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) { + override fun runtimeClassPaths(module: TestModule): List { + if (!module.targetPlatform.isJs()) return emptyList() + val jar = findJsLib() + return listOf(jar) + } +} + + +private const val ANNOTATIONS_JAR_DIR = "plugins/fir-plugin-prototype/plugin-annotations/build/libs/" +private val JVM_ANNOTATIONS_JAR_FILTER = createFilter("plugin-annotations-jvm", ".jar") +private val JS_ANNOTATIONS_KLIB_FILTER = createFilter("plugin-annotations-js", ".klib") + +private fun findJvmLib(): File { + return findLib("jvm", ".jar", JVM_ANNOTATIONS_JAR_FILTER) +} + +private fun findJsLib(): File { + return findLib("js", ".klib", JS_ANNOTATIONS_KLIB_FILTER) +} + +@Suppress("warnings") // TODO +private fun findLib(platform: String, extension: String, filter: FilenameFilter): File { + return findLibFromProperty(platform, extension) + ?: findLibByPath(filter) + ?: error("Lib with annotations does not exist. Please run :plugins:fir-plugin-prototype:plugin-annotations:distAnnotations or specify firPluginAnnotations.path system property") +} + +private fun createFilter(pattern: String, extension: String): FilenameFilter { + return FilenameFilter { _, name -> name.startsWith(pattern) && name.endsWith(extension) } +} + +private fun findLibByPath(filter: FilenameFilter): File? { + val libDir = File(ANNOTATIONS_JAR_DIR) + if (!libDir.exists() || !libDir.isDirectory) return null + return libDir.listFiles(filter)?.firstOrNull() +} + +/* + * Possible properties: + * - firPluginAnnotations.jvm.path + * - firPluginAnnotations.js.path + */ +private fun findLibFromProperty(platform: String, extension: String): File? { + val firPluginAnnotationsPath = System.getProperty("firPluginAnnotations.${platform}.path") ?: return null + return File(firPluginAnnotationsPath).takeIf { + it.isFile && + it.name.startsWith("plugin-annotations") && + it.name.endsWith(extension) + } +}