From 0d86ee448837f40dd4c7a3516ee06654b754d3ec Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Fri, 26 Apr 2024 13:00:10 +0300 Subject: [PATCH] Deduplicate code, update API dump, and fix wrong session closure, add doc --- .../api/analysis-kotlin-api.api | 3 +- .../SampleAnalysisEnvironmentCreator.kt | 15 ++- .../test/sample/SampleAnalysisTest.kt | 96 +++++++++++++++---- .../DescriptorSampleAnalysisEnvironment.kt | 17 +--- .../SymbolSampleAnalysisEnvironment.kt | 15 +-- 5 files changed, 94 insertions(+), 52 deletions(-) diff --git a/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api b/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api index 75cadd1b66..46a2ddd0d3 100644 --- a/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api +++ b/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api @@ -78,11 +78,12 @@ public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/Funct public abstract fun rewrite (Ljava/util/List;Ljava/util/List;)Ljava/lang/String; } -public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment { +public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment : java/io/Closeable { public abstract fun resolveSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet; } public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator { + public abstract fun create ()Lorg/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment; public abstract fun use (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt index 6fc6f9155c..c9d094c69c 100644 --- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt +++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator.kt @@ -16,7 +16,7 @@ public interface SampleAnalysisEnvironmentCreator { /** * Creates and configures the sample analysis environment for a limited-time use. * - * Configuring sample analysis environment is a rather expensive operation that takes up additional + * Configuring a sample analysis environment is a rather expensive operation that takes up additional * resources since Dokka needs to configure and analyze source roots additional to the main ones. * It's best to limit the scope of use and the lifetime of the created environment * so that the resources could be freed as soon as possible. @@ -36,5 +36,18 @@ public interface SampleAnalysisEnvironmentCreator { */ public fun use(block: SampleAnalysisEnvironment.() -> T): T + /** + * Creates a new instance of [SampleAnalysisEnvironment]. + * + * **WARNING**: This function offers a considerable amount of freedom and with it, + * the potential to misuse the API. + * A [SampleAnalysisEnvironment] once created needs to be manually closed + * otherwise it could lead to memory leaks, concurrency issues or other unexpected problems. + * + * Therefore, it's safest to use it through the [SampleAnalysisEnvironmentCreator.use] + * as it provides a controlled environment where everything is taken care of automatically. + * + * @return a new instance of [SampleAnalysisEnvironment] + */ public fun create(): SampleAnalysisEnvironment } diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt index 02ae6d969d..ba76b80fe5 100644 --- a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt +++ b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt @@ -44,31 +44,85 @@ class SampleAnalysisTest { testProject.useServices { context -> val sampleAnalysisEnvironment = sampleAnalysisEnvironmentCreator.create() - val sample = sampleAnalysisEnvironment.resolveSample( - sourceSet = context.singleSourceSet(), - fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations" - ) - assertNotNull(sample) + try { + val sample = sampleAnalysisEnvironment.resolveSample( + sourceSet = context.singleSourceSet(), + fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations" + ) + assertNotNull(sample) - val expectedImports = listOf( - "org.jetbrains.dokka.DokkaConfiguration", - "org.jetbrains.dokka.DokkaGenerator", - "org.jetbrains.dokka.utilities.DokkaLogger" - ) + val expectedImports = listOf( + "org.jetbrains.dokka.DokkaConfiguration", + "org.jetbrains.dokka.DokkaGenerator", + "org.jetbrains.dokka.utilities.DokkaLogger" + ) - val expectedBody = """ - val numbers = mutableListOf(1, 2, 3, 4) - numbers.add(5) - numbers.removeAt(1) - numbers[0] = 0 - numbers.shuffle() - if (numbers.size > 0) { - println(numbers) + val expectedBody = """ + val numbers = mutableListOf(1, 2, 3, 4) + numbers.add(5) + numbers.removeAt(1) + numbers[0] = 0 + numbers.shuffle() + if (numbers.size > 0) { + println(numbers) + } + """.trimIndent() + + assertEquals(expectedImports, sample.imports) + assertEquals(expectedBody, sample.body) + } finally { + sampleAnalysisEnvironment.close() + } + } + } + + @Test + fun `should resolve the same sample by multiple environments`() { + val testProject = kotlinJvmTestProject { + dokkaConfiguration { + kotlinSourceSet { + samples = setOf("/samples/collections.kt") } - """.trimIndent() + } + sampleFile("/samples/collections.kt", fqPackageName = "org.jetbrains.dokka.sample.collections") { + +""" + import org.jetbrains.dokka.DokkaConfiguration + import org.jetbrains.dokka.DokkaGenerator + import org.jetbrains.dokka.utilities.DokkaLogger + + fun specificPositionOperations() { + val numbers = mutableListOf(1, 2, 3, 4) + numbers.add(5) + numbers.removeAt(1) + numbers[0] = 0 + numbers.shuffle() + if (numbers.size > 0) { + println(numbers) + } + } + """ + } + } - assertEquals(expectedImports, sample.imports) - assertEquals(expectedBody, sample.body) + testProject.useServices { context -> + val sampleAnalysisEnvironment1 = sampleAnalysisEnvironmentCreator.create() + val sampleAnalysisEnvironment2 = sampleAnalysisEnvironmentCreator.create() + try { + val sample1 = sampleAnalysisEnvironment1.resolveSample( + sourceSet = context.singleSourceSet(), + fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations" + ) + val sample2 = sampleAnalysisEnvironment2.resolveSample( + sourceSet = context.singleSourceSet(), + fullyQualifiedLink = "org.jetbrains.dokka.sample.collections.specificPositionOperations" + ) + assertNotNull(sample1) + assertNotNull(sample2) + assertEquals(sample1, sample2) + } finally { + sampleAnalysisEnvironment1.close() + sampleAnalysisEnvironment2.close() + } } } diff --git a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSampleAnalysisEnvironment.kt b/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSampleAnalysisEnvironment.kt index 53d162ab32..cf29c0cc72 100644 --- a/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSampleAnalysisEnvironment.kt +++ b/dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSampleAnalysisEnvironment.kt @@ -50,20 +50,7 @@ internal class DescriptorSampleAnalysisEnvironmentCreator( // avoid memory leaks through the compiler's ThreadLocals. // Might not be relevant if the project stops using coroutines. return runBlocking(Dispatchers.Default) { - @OptIn(DokkaPluginApiPreview::class) - SamplesKotlinAnalysis( - sourceSets = context.configuration.sourceSets, - context = context, - projectKotlinAnalysis = descriptorAnalysisPlugin.querySingle { kotlinAnalysis } - ).use { kotlinAnalysis -> - val sampleAnalysis = DescriptorSampleAnalysisEnvironment( - kdocFinder = descriptorAnalysisPlugin.querySingle { kdocFinder }, - kotlinAnalysis = kotlinAnalysis, - sampleRewriter = sampleRewriter, - dokkaLogger = context.logger - ) - block(sampleAnalysis) - } + create().use(block) } } @@ -87,7 +74,7 @@ internal class DescriptorSampleAnalysisEnvironment( private val kotlinAnalysis: KotlinAnalysis, private val sampleRewriter: SampleRewriter?, private val dokkaLogger: DokkaLogger, -) : SampleAnalysisEnvironment, Closeable { +) : SampleAnalysisEnvironment { override fun resolveSample( sourceSet: DokkaConfiguration.DokkaSourceSet, diff --git a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt index 38487365b3..f5b7b59f5f 100644 --- a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt +++ b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt @@ -44,21 +44,9 @@ internal class SymbolSampleAnalysisEnvironmentCreator( rewriters.singleOrNull() } - override fun use(block: SampleAnalysisEnvironment.() -> T): T { return runBlocking(Dispatchers.Default) { - SamplesKotlinAnalysis( - sourceSets = context.configuration.sourceSets, - context = context - ).use { samplesKotlinAnalysis -> - val sampleAnalysisEnvironment = SymbolSampleAnalysisEnvironment( - samplesKotlinAnalysis = samplesKotlinAnalysis, - projectKotlinAnalysis = projectKotlinAnalysis, - sampleRewriter = sampleRewriter, - dokkaLogger = context.logger - ) - block(sampleAnalysisEnvironment) - } + create().use(block) } } @@ -189,7 +177,6 @@ private class SymbolSampleAnalysisEnvironment( override fun close() { samplesKotlinAnalysis.close() - projectKotlinAnalysis.close() } }