diff --git a/core/api/core.api b/core/api/core.api index 8b9e5c7b02..9c943c3fce 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -65,6 +65,7 @@ public abstract interface class org/jetbrains/dokka/DokkaConfiguration : java/io public abstract fun getCacheRoot ()Ljava/io/File; public abstract fun getDelayTemplateSubstitution ()Z public abstract fun getFailOnWarning ()Z + public abstract fun getFinalizeCoroutines ()Z public abstract fun getIncludes ()Ljava/util/Set; public abstract fun getModuleName ()Ljava/lang/String; public abstract fun getModuleVersion ()Ljava/lang/String; @@ -168,14 +169,15 @@ public abstract interface class org/jetbrains/dokka/DokkaConfigurationBuilder { public final class org/jetbrains/dokka/DokkaConfigurationImpl : org/jetbrains/dokka/DokkaConfiguration { public fun ()V - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;Z)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZZ)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component10 ()Z public final fun component11 ()Z public final fun component12 ()Z public final fun component13 ()Ljava/util/Set; public final fun component14 ()Z + public final fun component15 ()Z public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/io/File; public final fun component4 ()Ljava/io/File; @@ -184,12 +186,13 @@ public final class org/jetbrains/dokka/DokkaConfigurationImpl : org/jetbrains/do public final fun component7 ()Ljava/util/List; public final fun component8 ()Ljava/util/List; public final fun component9 ()Ljava/util/List; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;Z)Lorg/jetbrains/dokka/DokkaConfigurationImpl; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/DokkaConfigurationImpl;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZILjava/lang/Object;)Lorg/jetbrains/dokka/DokkaConfigurationImpl; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZZ)Lorg/jetbrains/dokka/DokkaConfigurationImpl; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/DokkaConfigurationImpl;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/io/File;ZLjava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZZLjava/util/Set;ZZILjava/lang/Object;)Lorg/jetbrains/dokka/DokkaConfigurationImpl; public fun equals (Ljava/lang/Object;)Z public fun getCacheRoot ()Ljava/io/File; public fun getDelayTemplateSubstitution ()Z public fun getFailOnWarning ()Z + public fun getFinalizeCoroutines ()Z public fun getIncludes ()Ljava/util/Set; public fun getModuleName ()Ljava/lang/String; public fun getModuleVersion ()Ljava/lang/String; diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index 9241d72825..a14775cbea 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -2,15 +2,12 @@ package org.jetbrains.dokka +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher import org.jetbrains.dokka.generation.GracefulGenerationExit import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.utilities.DokkaLogger -import kotlin.reflect.full.memberProperties -import kotlin.reflect.jvm.isAccessible /** * DokkaGenerator is the main entry point for generating documentation @@ -45,28 +42,12 @@ class DokkaGenerator( additionalPlugins: List = emptyList() ) = DokkaContext.create(configuration, logger, additionalPlugins) + @OptIn(DelicateCoroutinesApi::class) private fun finalizeCoroutines() { - runCatching { - Dispatchers.Default.closeExecutor() - - Dispatchers.IO.let { dispatcher -> - dispatcher::class.memberProperties.find { - it.name == "dispatcher" - }?.also { - it.isAccessible = true - }?.call(dispatcher) - }?.closeExecutor() + if (configuration.finalizeCoroutines) { + Dispatchers.shutdown() } } - - @OptIn(InternalCoroutinesApi::class) - private fun Any.closeExecutor() = (this as ExperimentalCoroutineDispatcher).also { - it.executor::class.members - .find { it.name == "close" } - ?.also { - it.isAccessible = true - }?.call(it.executor) - } } class Timer internal constructor(startTime: Long, private val logger: DokkaLogger?) { diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index 038a5bb777..ebd6ed61be 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -134,6 +134,25 @@ interface DokkaConfiguration : Serializable { val includes: Set val suppressInheritedMembers: Boolean + /** + * Whether coroutines dispatchers should be shutdown after + * generating documentation via [DokkaGenerator.generate]. + * + * It effectively stops all background threads associated with + * coroutines in order to make classes unloadable by the JVM, + * and rejects all new tasks with [RejectedExecutionException] + * + * This is primarily useful for multi-module builds where coroutines + * can be shut down after each module's partial task to avoid + * possible memory leaks. + * + * However, this can lead to problems in specific lifecycles where + * coroutines are shared and will be reused after documentation generation, + * and closing it down will leave the build in an inoperable state. + * One such example is unit tests, for which finalization should be disabled. + */ + val finalizeCoroutines: Boolean + enum class SerializationFormat : Serializable { JSON, XML } diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 4d23ce687b..d4f92f3341 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -19,6 +19,7 @@ data class DokkaConfigurationImpl( override val suppressObviousFunctions: Boolean = DokkaDefaults.suppressObviousFunctions, override val includes: Set = emptySet(), override val suppressInheritedMembers: Boolean = DokkaDefaults.suppressInheritedMembers, + override val finalizeCoroutines: Boolean = true, ) : DokkaConfiguration data class PluginConfigurationImpl( diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt index 804e02ce2b..623fcc2de5 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -54,7 +54,8 @@ class TestDokkaConfigurationBuilder { suppressObviousFunctions = suppressObviousFunctions, includes = includes.toSet(), suppressInheritedMembers = suppressInheritedMembers, - delayTemplateSubstitution = delayTemplateSubstitution + delayTemplateSubstitution = delayTemplateSubstitution, + finalizeCoroutines = false ) fun sourceSets(block: SourceSetsBuilder.() -> Unit) { diff --git a/gradle.properties b/gradle.properties index 49b900b736..dfc59909dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ dokka_publication_channels=maven-central-snapshot&space-dokka-dev dokka_integration_test_parallelism=2 # Versions kotlin_version=1.6.10 -coroutines_version=1.5.1 +coroutines_version=1.6.0 kotlinx_html_version=0.7.3 kotlin_plugin_version=211-1.6.10-release-923-IJ7442.40 jsoup_version=1.13.1 diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 9b88a1707a..138924088a 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -43,7 +43,8 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { val files = TestOutputWriter() open val configuration = DokkaConfigurationImpl( - sourceSets = listOf(js, jvm, native) + sourceSets = listOf(js, jvm, native), + finalizeCoroutines = false ) override val context = MockContext( diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt index 1fa78423fc..4634884955 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt @@ -21,7 +21,7 @@ abstract class GfmRenderingOnlyTestBase : RenderingOnlyTestBase() { DokkaBase().externalLocationProviderFactory to ::DefaultExternalLocationProviderFactory, GfmPlugin().gfmPreprocessors to { RootCreator }, - testConfiguration = DokkaConfigurationImpl(moduleName = "root") + testConfiguration = DokkaConfigurationImpl(moduleName = "root", finalizeCoroutines = false) ) override val renderedContent: String by lazy { diff --git a/runners/cli/api/cli.api b/runners/cli/api/cli.api index 208235aef5..cdd051ccbe 100644 --- a/runners/cli/api/cli.api +++ b/runners/cli/api/cli.api @@ -65,6 +65,7 @@ public final class org/jetbrains/dokka/GlobalArguments : org/jetbrains/dokka/Dok public fun getCacheRoot ()Ljava/io/File; public fun getDelayTemplateSubstitution ()Z public fun getFailOnWarning ()Z + public fun getFinalizeCoroutines ()Z public final fun getGlobalLinks ()Ljava/util/List; public final fun getGlobalPackageOptions ()Ljava/util/List; public final fun getGlobalSrcLink ()Ljava/util/List; diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 1dc32a45a5..4768828b89 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -88,6 +88,8 @@ class GlobalArguments(args: Array) : DokkaConfiguration { description = "Suppress members inherited from other classes" ).default(DokkaDefaults.suppressInheritedMembers) + override val finalizeCoroutines: Boolean = true + val globalPackageOptions by parser.option( ArgType.String, description = "List of package source sets in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" "