diff options
| author | Andrzej Ratajczak <andrzej.ratajczak98@gmail.com> | 2020-09-22 11:08:16 +0200 |
|---|---|---|
| committer | Andrzej Ratajczak <32793002+BarkingBad@users.noreply.github.com> | 2020-10-02 12:40:50 +0200 |
| commit | 8de5296b18083361055d11acf6d522c1eef821a4 (patch) | |
| tree | 5e4f4c42bf801f33c40c4efeb5601e0fc4523e36 | |
| parent | 71b03f6d311c6ebfdf67c593e97a7483a64844f4 (diff) | |
| download | dokka-8de5296b18083361055d11acf6d522c1eef821a4.tar.gz dokka-8de5296b18083361055d11acf6d522c1eef821a4.tar.bz2 dokka-8de5296b18083361055d11acf6d522c1eef821a4.zip | |
Make translators run in parallel.
9 files changed, 697 insertions, 542 deletions
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 69ebce06..f063496e 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -14,4 +14,4 @@ <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> </codeStyleSettings> </code_scheme> -</component>
\ No newline at end of file +</component> diff --git a/core/build.gradle.kts b/core/build.gradle.kts index f4fb1017..971f08f4 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -12,6 +12,9 @@ dependencies { implementation("org.jsoup:jsoup:1.12.1") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.1") + val coroutines_version: String by project + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") + testImplementation(project(":core:test-api")) testImplementation(kotlin("test-junit")) } diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index 6f42b259..bee85325 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -9,6 +9,8 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.utilities.report +import kotlinx.coroutines.* +import org.jetbrains.dokka.utilities.parallelMap /** @@ -73,9 +75,10 @@ class DokkaGenerator( fun createDocumentationModels( context: DokkaContext - ) = context.configuration.sourceSets - .flatMap { sourceSet -> translateSources(sourceSet, context) } - .also { modules -> if (modules.isEmpty()) exitGenerationGracefully("Nothing to document") } + ) = runBlocking(Dispatchers.Default) { + context.configuration.sourceSets.parallelMap { sourceSet -> translateSources(sourceSet, context) }.flatten() + .also { modules -> if (modules.isEmpty()) exitGenerationGracefully("Nothing to document") } + } fun transformDocumentationModelBeforeMerge( modulesFromPlatforms: List<DModule>, @@ -133,8 +136,8 @@ class DokkaGenerator( } } - private fun translateSources(sourceSet: DokkaSourceSet, context: DokkaContext) = - context[CoreExtensions.sourceToDocumentableTranslator].map { + private suspend fun translateSources(sourceSet: DokkaSourceSet, context: DokkaContext) = + context[CoreExtensions.sourceToDocumentableTranslator].parallelMap { it.invoke(sourceSet, context) } } diff --git a/core/src/main/kotlin/plugability/LazyEvaluated.kt b/core/src/main/kotlin/plugability/LazyEvaluated.kt index c0c271f4..17fad525 100644 --- a/core/src/main/kotlin/plugability/LazyEvaluated.kt +++ b/core/src/main/kotlin/plugability/LazyEvaluated.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka.plugability internal class LazyEvaluated<T : Any> private constructor(private val recipe: ((DokkaContext) -> T)? = null, private var value: T? = null) { + @Synchronized internal fun get(context: DokkaContext): T { if(value == null) { value = recipe?.invoke(context) @@ -13,4 +14,4 @@ internal class LazyEvaluated<T : Any> private constructor(private val recipe: (( fun <T : Any> fromInstance(value: T) = LazyEvaluated(value = value) fun <T : Any> fromRecipe(recipe: (DokkaContext) -> T) = LazyEvaluated(recipe = recipe) } -}
\ No newline at end of file +} diff --git a/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt b/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt index 6bc8fb14..8ac59a15 100644 --- a/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt +++ b/core/src/main/kotlin/transformers/sources/SourceToDocumentableTranslator.kt @@ -5,5 +5,5 @@ import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.plugability.DokkaContext interface SourceToDocumentableTranslator { - fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule -}
\ No newline at end of file + suspend fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule +} diff --git a/core/src/main/kotlin/utilities/parallelCollectionOperations.kt b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt new file mode 100644 index 00000000..b3191e8b --- /dev/null +++ b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt @@ -0,0 +1,17 @@ +package org.jetbrains.dokka.utilities + +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope + +suspend inline fun <A, B> Iterable<A>.parallelMap(crossinline f: suspend (A) -> B): List<B> = coroutineScope { + map { async { f(it) } }.awaitAll() +} + +suspend inline fun <A, B> Iterable<A>.parallelMapNotNull(crossinline f: suspend (A) -> B?): List<B> = coroutineScope { + map { async { f(it) } }.awaitAll().filterNotNull() +} + +suspend inline fun <A> Iterable<A>.parallelForEach(crossinline f: suspend (A) -> Unit): Unit = coroutineScope { + map { async { f(it) } }.awaitAll() +} diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 47180042..5c0f54d8 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -228,4 +228,4 @@ fun ContentPage.sourceSets() = this.content.sourceSets fun ContentEmbeddedResource.isImage(): Boolean { val imageExtensions = setOf("png", "jpg", "jpeg", "gif", "bmp", "tif", "webp", "svg") return File(address).extension.toLowerCase() in imageExtensions -}
\ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index ecfd5172..d64a7b29 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -1,5 +1,9 @@ package org.jetbrains.dokka.base.translators.descriptors +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.withContext import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.analysis.DokkaResolutionFacade @@ -18,8 +22,9 @@ import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType +import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.dokka.utilities.parallelMapNotNull import org.jetbrains.kotlin.builtins.isExtensionFunctionType -import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.isJvmStaticInObjectOrClassOrInterface import org.jetbrains.kotlin.descriptors.* @@ -27,7 +32,6 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies import org.jetbrains.kotlin.idea.kdoc.findKDoc import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink import org.jetbrains.kotlin.load.kotlin.toSourceElement @@ -40,7 +44,6 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.LocalClass import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.NormalClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceElement @@ -49,6 +52,7 @@ import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import java.lang.IllegalStateException import java.nio.file.Paths import org.jetbrains.kotlin.resolve.constants.AnnotationValue as ConstantsAnnotationValue import org.jetbrains.kotlin.resolve.constants.ArrayValue as ConstantsArrayValue @@ -59,7 +63,7 @@ class DefaultDescriptorToDocumentableTranslator( private val kotlinAnalysis: KotlinAnalysis ) : SourceToDocumentableTranslator { - override fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { + override suspend fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { val (environment, facade) = kotlinAnalysis[sourceSet] val packageFragments = environment.getSourceFiles().asSequence() .map { it.packageFqName } @@ -68,7 +72,7 @@ class DefaultDescriptorToDocumentableTranslator( .toList() return DokkaDescriptorVisitor(sourceSet, kotlinAnalysis[sourceSet].facade, context.logger).run { - packageFragments.mapNotNull { it.safeAs<PackageFragmentDescriptor>() }.map { + packageFragments.mapNotNull { it.safeAs<PackageFragmentDescriptor>() }.parallelMap { visitPackageFragmentDescriptor( it, DRIWithPlatformInfo(DRI.topLevel, emptyMap()) @@ -97,11 +101,7 @@ private class DokkaDescriptorVisitor( private val sourceSet: DokkaSourceSet, private val resolutionFacade: DokkaResolutionFacade, private val logger: DokkaLogger -) : DeclarationDescriptorVisitorEmptyBodies<Documentable, DRIWithPlatformInfo>() { - override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor, parent: DRIWithPlatformInfo): Nothing { - throw IllegalStateException("${javaClass.simpleName} should never enter ${descriptor.javaClass.simpleName}") - } - +) { private fun Collection<DeclarationDescriptor>.filterDescriptorsInSourceSet() = filter { it.toSourceElement.containingFile.toString().let { path -> path.isNotBlank() && sourceSet.sourceRoots.any { root -> @@ -112,26 +112,34 @@ private class DokkaDescriptorVisitor( private fun <T> T.toSourceSetDependent() = mapOf(sourceSet to this) - override fun visitPackageFragmentDescriptor( + suspend fun visitPackageFragmentDescriptor( descriptor: PackageFragmentDescriptor, parent: DRIWithPlatformInfo ): DPackage { val name = descriptor.fqName.asString().takeUnless { it.isBlank() } ?: "" val driWithPlatform = DRI(packageName = name).withEmptyInfo() val scope = descriptor.getMemberScope() - - return DPackage( - dri = driWithPlatform.dri, - functions = scope.functions(driWithPlatform, true), - properties = scope.properties(driWithPlatform, true), - classlikes = scope.classlikes(driWithPlatform, true), - typealiases = scope.typealiases(driWithPlatform, true), - documentation = descriptor.resolveDescriptorData(), - sourceSets = setOf(sourceSet) - ) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind(true) + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + val typealiases = async { descriptorsWithKind.typealiases.visitTypealiases(driWithPlatform) } + + DPackage( + dri = driWithPlatform.dri, + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + typealiases = typealiases.await(), + documentation = descriptor.resolveDescriptorData(), + sourceSets = setOf(sourceSet) + ) + } } - override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClasslike = + private suspend fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClasslike = when (descriptor.kind) { ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent) ClassKind.OBJECT -> objectDescriptor(descriptor, parent) @@ -140,37 +148,46 @@ private class DokkaDescriptorVisitor( else -> classDescriptor(descriptor, parent) } - private fun interfaceDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DInterface { + private suspend fun interfaceDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DInterface { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect val isActual = descriptor.isActual val info = descriptor.resolveClassDescriptionData() - return DInterface( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - classlikes = scope.classlikes(driWithPlatform), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() }, - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } + + DInterface( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + sources = descriptor.createSources(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + supertypes = info.supertypes.toSourceSetDependent(), + documentation = info.docs, + generics = generics.await(), + companion = descriptor.companion(driWithPlatform), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + ) ) - ) + } } - private fun objectDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DObject { + private suspend fun objectDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DObject { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect @@ -178,109 +195,149 @@ private class DokkaDescriptorVisitor( val info = descriptor.resolveClassDescriptionData() - return DObject( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - classlikes = scope.classlikes(driWithPlatform), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + + DObject( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + sources = descriptor.createSources(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + supertypes = info.supertypes.toSourceSetDependent(), + documentation = info.docs, + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + ) ) - ) + } + + } - private fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnum { + private suspend fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnum { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect val isActual = descriptor.isActual val info = descriptor.resolveClassDescriptionData() - return DEnum( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - entries = scope.enumEntries(driWithPlatform), - constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) }, - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - classlikes = scope.classlikes(driWithPlatform), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + val constructors = async { descriptor.constructors.parallelMap { visitConstructorDescriptor(it, driWithPlatform) } } + val entries = async { descriptorsWithKind.enumEntries.visitEnumEntries(driWithPlatform) } + + DEnum( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + entries = entries.await(), + constructors = constructors.await(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + sources = descriptor.createSources(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + supertypes = info.supertypes.toSourceSetDependent(), + documentation = info.docs, + companion = descriptor.companion(driWithPlatform), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) + ) ) - ) + } } - private fun enumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnumEntry { + private suspend fun visitEnumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnumEntry { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect - return DEnumEntry( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - documentation = descriptor.resolveDescriptorData(), - classlikes = scope.classlikes(driWithPlatform), - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - sourceSets = setOf(sourceSet), - expectPresentInSet = sourceSet.takeIf { isExpect }, - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ConstructorValues(descriptor.getAppliedConstructorParameters().toSourceSetDependent()) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + + DEnumEntry( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + documentation = descriptor.resolveDescriptorData(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + sourceSets = setOf(sourceSet), + expectPresentInSet = sourceSet.takeIf { isExpect }, + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ConstructorValues(descriptor.getAppliedConstructorParameters().toSourceSetDependent()) + ) ) - ) + } } - fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation { + private suspend fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect val isActual = descriptor.isActual - return DAnnotation( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - documentation = descriptor.resolveDescriptorData(), - classlikes = scope.classlikes(driWithPlatform), - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() - ), - companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() }, - constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) }, - sources = descriptor.createSources() - ) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } + val constructors = async { descriptor.constructors.parallelMap { visitConstructorDescriptor(it, driWithPlatform) } } + + DAnnotation( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + documentation = descriptor.resolveDescriptorData(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + ), + companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + generics = generics.await(), + constructors = constructors.await(), + sources = descriptor.createSources() + ) + } + + } - private fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClass { + private suspend fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClass { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect @@ -288,163 +345,188 @@ private class DokkaDescriptorVisitor( val info = descriptor.resolveClassDescriptionData() val actual = descriptor.createSources() - return DClass( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - constructors = descriptor.constructors.map { - visitConstructorDescriptor( - it, - if (it.isPrimary) DRIWithPlatformInfo(driWithPlatform.dri, actual) - else DRIWithPlatformInfo(driWithPlatform.dri, emptyMap()) + return coroutineScope { + val descriptorsWithKind = scope.getDescriptorsWithKind() + + val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } + val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } + val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } + val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } + val constructors = async { + descriptor.constructors.parallelMap { + visitConstructorDescriptor( + it, + if (it.isPrimary) DRIWithPlatformInfo(driWithPlatform.dri, actual) + else DRIWithPlatformInfo(driWithPlatform.dri, emptyMap()) + ) + } + } + + DClass( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + constructors = constructors.await(), + functions = functions.await(), + properties = properties.await(), + classlikes = classlikes.await(), + sources = actual, + expectPresentInSet = sourceSet.takeIf { isExpect }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + supertypes = info.supertypes.toSourceSetDependent(), + generics = generics.await(), + documentation = info.docs, + modifier = descriptor.modifier().toSourceSetDependent(), + companion = descriptor.companion(driWithPlatform), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll<DClass>( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) - }, - functions = scope.functions(driWithPlatform), - properties = scope.properties(driWithPlatform), - classlikes = scope.classlikes(driWithPlatform), - sources = actual, - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() }, - documentation = info.docs, - modifier = descriptor.modifier().toSourceSetDependent(), - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll<DClass>( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) - ) + } } - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): DProperty { + private suspend fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): DProperty { val dri = parent.dri.copy(callable = Callable.from(descriptor)) val isExpect = descriptor.isExpect val isActual = descriptor.isActual val actual = descriptor.createSources() - return DProperty( - dri = dri, - name = descriptor.name.asString(), - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - sources = actual, - getter = descriptor.accessors.filterIsInstance<PropertyGetterDescriptor>().singleOrNull()?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri) - }, - setter = descriptor.accessors.filterIsInstance<PropertySetterDescriptor>().singleOrNull()?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri) - }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = descriptor.resolveDescriptorData(), - modifier = descriptor.modifier().toSourceSetDependent(), - type = descriptor.returnType!!.toBound(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - generics = descriptor.typeParameters.map { it.toVariantTypeParameter() }, - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll(listOfNotNull( - (descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField() - .toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotationsWithBackingField().toSourceSetDependent().toAnnotations(), - descriptor.getDefaultValue()?.let { DefaultValue(it) } - )) - ) + + return coroutineScope { + val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } + + DProperty( + dri = dri, + name = descriptor.name.asString(), + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) + }, + sources = actual, + getter = descriptor.accessors.filterIsInstance<PropertyGetterDescriptor>().singleOrNull()?.let { + visitPropertyAccessorDescriptor(it, descriptor, dri) + }, + setter = descriptor.accessors.filterIsInstance<PropertySetterDescriptor>().singleOrNull()?.let { + visitPropertyAccessorDescriptor(it, descriptor, dri) + }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + documentation = descriptor.resolveDescriptorData(), + modifier = descriptor.modifier().toSourceSetDependent(), + type = descriptor.returnType!!.toBound(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + sourceSets = setOf(sourceSet), + generics = generics.await(), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll(listOfNotNull( + (descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField() + .toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotationsWithBackingField().toSourceSetDependent().toAnnotations(), + descriptor.getDefaultValue()?.let { DefaultValue(it) } + )) + ) + } } - fun CallableMemberDescriptor.createDRI(wasOverridenBy: DRI? = null): Pair<DRI, DRI?> = + private fun CallableMemberDescriptor.createDRI(wasOverridenBy: DRI? = null): Pair<DRI, DRI?> = if (kind == CallableMemberDescriptor.Kind.DECLARATION || overriddenDescriptors.isEmpty()) |
