diff --git a/core/src/main/kotlin/utilities/parallelCollectionOperations.kt b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
index b3191e8b09..35ad48fd36 100644
--- a/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
+++ b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
@@ -1,8 +1,6 @@
package org.jetbrains.dokka.utilities
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.*
suspend inline fun Iterable.parallelMap(crossinline f: suspend (A) -> B): List = coroutineScope {
map { async { f(it) } }.awaitAll()
@@ -13,5 +11,5 @@ suspend inline fun Iterable.parallelMapNotNull(crossinline f: suspend
}
suspend inline fun Iterable.parallelForEach(crossinline f: suspend (A) -> Unit): Unit = coroutineScope {
- map { async { f(it) } }.awaitAll()
+ forEach { launch { f(it) } }
}
diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt
index 73023a8688..aafc616359 100644
--- a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt
+++ b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt
@@ -1,14 +1,8 @@
package org.jetbrains.dokka.base.transformers.documentables
import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.channels.ClosedReceiveChannelException
-import kotlinx.coroutines.channels.ReceiveChannel
-import kotlinx.coroutines.channels.SendChannel
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.channels.*
+import org.jetbrains.dokka.base.transformers.documentables.utils.ClassGraphBuilder
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.DriOfAny
import org.jetbrains.dokka.model.*
@@ -17,97 +11,138 @@ import org.jetbrains.dokka.model.properties.MergeStrategy
import org.jetbrains.dokka.model.properties.plus
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer
+import org.jetbrains.kotlin.utils.addToStdlib.popLast
+import org.jetbrains.dokka.utilities.parallelForEach
+import org.jetbrains.dokka.utilities.parallelMap
class ExtensionExtractorTransformer : DocumentableTransformer {
override fun invoke(original: DModule, context: DokkaContext): DModule = runBlocking(Dispatchers.Default) {
+ val classGraph = async { ClassGraphBuilder()(original) }
+
val channel = Channel>(10)
launch {
- coroutineScope {
- original.packages.forEach { launch { collectExtensions(it, channel) } }
- }
+ original.packages.parallelForEach { collectExtensions(it, channel) }
channel.close()
}
- val extensionMap = channel.consumeAsFlow().toList().toMultiMap()
+ val extensionMap = channel.toList().toMultiMap()
- val newPackages = original.packages.map { async { it.addExtensionInformation(extensionMap) } }
- original.copy(packages = newPackages.awaitAll())
+ val newPackages = original.packages.parallelMap { it.addExtensionInformation(classGraph.await(), extensionMap) }
+ original.copy(packages = newPackages)
}
-}
-private suspend fun T.addExtensionInformation(
- extensionMap: Map>
-): T = coroutineScope {
- val newClasslikes = (this@addExtensionInformation as? WithScope)
- ?.classlikes
- ?.map { async { it.addExtensionInformation(extensionMap) } }
- .orEmpty()
-
- @Suppress("UNCHECKED_CAST")
- when (this@addExtensionInformation) {
- is DPackage -> {
- val newTypealiases = typealiases.map { async { it.addExtensionInformation(extensionMap) } }
- copy(classlikes = newClasslikes.awaitAll(), typealiases = newTypealiases.awaitAll())
+ private suspend fun collectExtensions(
+ documentable: Documentable,
+ channel: SendChannel>
+ ): Unit = coroutineScope {
+ if (documentable is WithScope) {
+ documentable.classlikes.forEach {
+ launch { collectExtensions(it, channel) }
+ }
+
+ if (documentable is DObject || documentable is DPackage) {
+ (documentable.properties.asSequence() + documentable.functions.asSequence())
+ .flatMap { it.asPairsWithReceiverDRIs() }
+ .forEach { channel.send(it) }
+ }
}
- is DClass -> copy(classlikes = newClasslikes.awaitAll(), extra = extra + extensionMap.find(dri))
- is DEnum -> copy(classlikes = newClasslikes.awaitAll(), extra = extra + extensionMap.find(dri))
- is DInterface -> copy(classlikes = newClasslikes.awaitAll(), extra = extra + extensionMap.find(dri))
- is DObject -> copy(classlikes = newClasslikes.awaitAll(), extra = extra + extensionMap.find(dri))
- is DAnnotation -> copy(classlikes = newClasslikes.awaitAll(), extra = extra + extensionMap.find(dri))
- is DTypeAlias -> copy(extra = extra + extensionMap.find(dri))
- else -> throw IllegalStateException(
- "${this@addExtensionInformation::class.simpleName} is not expected to have extensions"
- )
- } as T
-}
+ }
-private fun Map>.find(dri: DRI) = get(dri)?.toSet()?.let(::CallableExtensions)
+ private suspend fun T.addExtensionInformation(
+ classGraph: SourceSetDependent