From 8de5296b18083361055d11acf6d522c1eef821a4 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 22 Sep 2020 11:08:16 +0200 Subject: Make translators run in parallel. --- .../src/main/kotlin/renderers/DefaultRenderer.kt | 2 +- .../DefaultDescriptorToDocumentableTranslator.kt | 831 ++++++++++++--------- .../psi/DefaultPsiToDocumentableTranslator.kt | 364 ++++----- 3 files changed, 664 insertions(+), 533 deletions(-) (limited to 'plugins/base/src') 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() }.map { + packageFragments.mapNotNull { it.safeAs() }.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() { - override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor, parent: DRIWithPlatformInfo): Nothing { - throw IllegalStateException("${javaClass.simpleName} should never enter ${descriptor.javaClass.simpleName}") - } - +) { private fun Collection.filterDescriptorsInSourceSet() = filter { it.toSourceElement.containingFile.toString().let { path -> path.isNotBlank() && sourceSet.sourceRoots.any { root -> @@ -112,26 +112,34 @@ private class DokkaDescriptorVisitor( private fun 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( + 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( - 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().singleOrNull()?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri) - }, - setter = descriptor.accessors.filterIsInstance().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().singleOrNull()?.let { + visitPropertyAccessorDescriptor(it, descriptor, dri) + }, + setter = descriptor.accessors.filterIsInstance().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 = + private fun CallableMemberDescriptor.createDRI(wasOverridenBy: DRI? = null): Pair = if (kind == CallableMemberDescriptor.Kind.DECLARATION || overriddenDescriptors.isEmpty()) Pair(DRI.from(this), wasOverridenBy) else overriddenDescriptors.first().createDRI(DRI.from(this)) - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): DFunction { + private suspend fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): DFunction { val (dri, inheritedFrom) = descriptor.createDRI() val isExpect = descriptor.isExpect val isActual = descriptor.isActual val actual = descriptor.createSources() - return DFunction( - dri = dri, - name = descriptor.name.asString(), - isConstructor = false, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - parameters = descriptor.valueParameters.mapIndexed { index, desc -> - parameter(index, desc, DRIWithPlatformInfo(dri, actual)) - }, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sources = actual, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = descriptor.typeParameters.map { it.toVariantTypeParameter() }, - documentation = descriptor.takeIf { it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED } - ?.resolveDescriptorData() ?: emptyMap(), - modifier = descriptor.modifier().toSourceSetDependent(), - type = descriptor.returnType!!.toBound(), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - InheritedFunction(inheritedFrom.toSourceSetDependent()), - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + return coroutineScope { + val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } + + DFunction( + dri = dri, + name = descriptor.name.asString(), + isConstructor = false, + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) + }, + parameters = descriptor.valueParameters.mapIndexed { index, desc -> + parameter(index, desc, DRIWithPlatformInfo(dri, actual)) + }, + expectPresentInSet = sourceSet.takeIf { isExpect }, + sources = actual, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + generics = generics.await(), + documentation = descriptor.takeIf { it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED } + ?.resolveDescriptorData() ?: emptyMap(), + modifier = descriptor.modifier().toSourceSetDependent(), + type = descriptor.returnType!!.toBound(), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + InheritedFunction(inheritedFrom.toSourceSetDependent()), + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + ) ) - ) + } } - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): DFunction { + suspend fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): DFunction { val name = descriptor.constructedClass.name.toString() val dri = parent.dri.copy(callable = Callable.from(descriptor, name)) val actual = descriptor.createSources() val isExpect = descriptor.isExpect val isActual = descriptor.isActual - return DFunction( - dri = dri, - name = name, - isConstructor = true, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - parameters = descriptor.valueParameters.mapIndexed { index, desc -> - parameter(index, desc, DRIWithPlatformInfo(dri, actual)) - }, - sources = actual, - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = descriptor.resolveDescriptorData().let { sourceSetDependent -> - if (descriptor.isPrimary) { - sourceSetDependent.map { entry -> - Pair( - entry.key, - entry.value.copy(children = (entry.value.children.find { it is Constructor }?.root?.let { constructor -> - listOf(Description(constructor)) - } ?: emptyList()) + entry.value.children.filterIsInstance())) - }.toMap() - } else { - sourceSetDependent + return coroutineScope { + val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } + + DFunction( + dri = dri, + name = name, + isConstructor = true, + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) + }, + parameters = descriptor.valueParameters.mapIndexed { index, desc -> + parameter(index, desc, DRIWithPlatformInfo(dri, actual)) + }, + sources = actual, + expectPresentInSet = sourceSet.takeIf { isExpect }, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + documentation = descriptor.resolveDescriptorData().let { sourceSetDependent -> + if (descriptor.isPrimary) { + sourceSetDependent.map { entry -> + Pair( + entry.key, + entry.value.copy(children = (entry.value.children.find { it is Constructor }?.root?.let { constructor -> + listOf(Description(constructor)) + } ?: emptyList()) + entry.value.children.filterIsInstance())) + }.toMap() + } else { + sourceSetDependent + } + }, + type = descriptor.returnType.toBound(), + modifier = descriptor.modifier().toSourceSetDependent(), + generics = generics.await(), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + ).let { + if (descriptor.isPrimary) { + it + PrimaryConstructorExtra + } else it } - }, - type = descriptor.returnType.toBound(), - modifier = descriptor.modifier().toSourceSetDependent(), - generics = descriptor.typeParameters.map { it.toVariantTypeParameter() }, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() - ).let { - if (descriptor.isPrimary) { - it + PrimaryConstructorExtra - } else it - } - ) + ) + } } - override fun visitReceiverParameterDescriptor( + private suspend fun visitReceiverParameterDescriptor( descriptor: ReceiverParameterDescriptor, parent: DRIWithPlatformInfo ) = DParameter( @@ -457,7 +539,7 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll(descriptor.getAnnotations().toSourceSetDependent().toAnnotations()) ) - private fun visitPropertyAccessorDescriptor( + private suspend fun visitPropertyAccessorDescriptor( descriptor: PropertyAccessorDescriptor, propertyDescriptor: PropertyDescriptor, parent: DRI @@ -467,7 +549,7 @@ private class DokkaDescriptorVisitor( val isExpect = descriptor.isExpect val isActual = descriptor.isActual - fun PropertyDescriptor.asParameter(parent: DRI) = + suspend fun PropertyDescriptor.asParameter(parent: DRI) = DParameter( parent.copy(target = PointingToCallableParameters(parameterIndex = 1)), this.name.asString(), @@ -494,52 +576,60 @@ private class DokkaDescriptorVisitor( listOf(propertyDescriptor.asParameter(dri)) } - return DFunction( - dri, - name, - isConstructor = false, - parameters = parameters, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = descriptor.resolveDescriptorData(), - type = descriptor.returnType!!.toBound(), - generics = descriptor.typeParameters.map { it.toVariantTypeParameter() }, - modifier = descriptor.modifier().toSourceSetDependent(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor( - it, - DRIWithPlatformInfo(dri, descriptor.createSources()) + return coroutineScope { + val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } + + DFunction( + dri, + name, + isConstructor = false, + parameters = parameters, + visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), + documentation = descriptor.resolveDescriptorData(), + type = descriptor.returnType!!.toBound(), + generics = generics.await(), + modifier = descriptor.modifier().toSourceSetDependent(), + expectPresentInSet = sourceSet.takeIf { isExpect }, + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor( + it, + DRIWithPlatformInfo(dri, descriptor.createSources()) + ) + }, + sources = descriptor.createSources(), + sourceSets = setOf(sourceSet), + isExpectActual = (isExpect || isActual), + extra = PropertyContainer.withAll( + descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), + descriptor.getAnnotations().toSourceSetDependent().toAnnotations() ) - }, - sources = descriptor.createSources(), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() ) - ) + } } - override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, parent: DRIWithPlatformInfo?) = + private suspend fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, parent: DRIWithPlatformInfo?) = with(descriptor) { - DTypeAlias( - dri = DRI.from(this), - name = name.asString(), - type = defaultType.toBound(), - expectPresentInSet = null, - underlyingType = underlyingType.toBound().toSourceSetDependent(), - visibility = visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = resolveDescriptorData(), - sourceSets = setOf(sourceSet), - generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() }, - extra = PropertyContainer.withAll( - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + coroutineScope { + val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } + + DTypeAlias( + dri = DRI.from(this@with), + name = name.asString(), + type = defaultType.toBound(), + expectPresentInSet = null, + underlyingType = underlyingType.toBound().toSourceSetDependent(), + visibility = visibility.toDokkaVisibility().toSourceSetDependent(), + documentation = resolveDescriptorData(), + sourceSets = setOf(sourceSet), + generics = generics.await(), + extra = PropertyContainer.withAll( + descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + ) ) - ) + } } - private fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = + private suspend fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = DParameter( dri = parent.dri.copy(target = PointingToCallableParameters(index)), name = descriptor.name.asString(), @@ -554,77 +644,100 @@ private class DokkaDescriptorVisitor( )) ) - private fun MemberScope.getContributedDescriptors(kindFilter: DescriptorKindFilter, shouldFilter: Boolean) = - getContributedDescriptors(kindFilter) { true }.let { + private data class DescriptorsWithKind( + val functions: List, + val properties: List, + val classlikes: List, + val typealiases: List, + val enumEntries: List + ) + + private suspend fun MemberScope.getDescriptorsWithKind(shouldFilter: Boolean = false): DescriptorsWithKind { + val descriptors = getContributedDescriptors { true }.let { if (shouldFilter) it.filterDescriptorsInSourceSet() else it } - private fun MemberScope.functions(parent: DRIWithPlatformInfo, packageLevel: Boolean = false): List = - getContributedDescriptors(DescriptorKindFilter.FUNCTIONS, packageLevel) - .filterIsInstance() - .map { visitFunctionDescriptor(it, parent) } + class EnumEntryDescriptor + + val groupedDescriptors = descriptors.groupBy { when { + it is FunctionDescriptor -> FunctionDescriptor::class + it is PropertyDescriptor -> PropertyDescriptor::class + it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY -> ClassDescriptor::class + it is TypeAliasDescriptor -> TypeAliasDescriptor::class + it is ClassDescriptor && it.kind == ClassKind.ENUM_ENTRY -> EnumEntryDescriptor::class + else -> IllegalStateException::class + } } + + return DescriptorsWithKind( + (groupedDescriptors[FunctionDescriptor::class] ?: emptyList()) as List, + (groupedDescriptors[PropertyDescriptor::class] ?: emptyList()) as List, + (groupedDescriptors[ClassDescriptor::class] ?: emptyList()) as List, + (groupedDescriptors[TypeAliasDescriptor::class] ?: emptyList()) as List, + (groupedDescriptors[EnumEntryDescriptor::class] ?: emptyList()) as List + ) + } - private fun MemberScope.properties(parent: DRIWithPlatformInfo, packageLevel: Boolean = false): List = - getContributedDescriptors(DescriptorKindFilter.VALUES, packageLevel) - .filterIsInstance() - .map { visitPropertyDescriptor(it, parent) } + private suspend fun List.visitFunctions(parent: DRIWithPlatformInfo): List = + coroutineScope { parallelMap { visitFunctionDescriptor(it, parent) } } - private fun MemberScope.classlikes(parent: DRIWithPlatformInfo, packageLevel: Boolean = false): List = - getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS, packageLevel) - .filter { it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY } - .map { visitClassDescriptor(it as ClassDescriptor, parent) } + private suspend fun List.visitProperties(parent: DRIWithPlatformInfo): List = + coroutineScope { parallelMap { visitPropertyDescriptor(it, parent) } } - private fun MemberScope.typealiases(parent: DRIWithPlatformInfo, packageLevel: Boolean = false): List = - getContributedDescriptors(DescriptorKindFilter.TYPE_ALIASES, packageLevel) - .filterIsInstance() - .map { visitTypeAliasDescriptor(it, parent) } + private suspend fun List.visitClasslikes(parent: DRIWithPlatformInfo): List = + coroutineScope { parallelMap { visitClassDescriptor(it, parent) } } - private fun MemberScope.enumEntries(parent: DRIWithPlatformInfo): List = - this.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) { true } - .filterIsInstance() - .filter { it.kind == ClassKind.ENUM_ENTRY } - .map { enumEntryDescriptor(it, parent) } + private suspend fun List.visitTypealiases(parent: DRIWithPlatformInfo): List = + coroutineScope { parallelMap { visitTypeAliasDescriptor(it, parent) } } + private suspend fun List.visitEnumEntries(parent: DRIWithPlatformInfo): List = + coroutineScope { parallelMap { visitEnumEntryDescriptor(it, parent) } } - private fun DeclarationDescriptor.resolveDescriptorData(): SourceSetDependent = + private suspend fun DeclarationDescriptor.resolveDescriptorData(): SourceSetDependent = getDocumentation()?.toSourceSetDependent() ?: emptyMap() - private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { - fun toTypeConstructor(kt: KotlinType) = - GenericTypeConstructor( - DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), - kt.arguments.map { it.toProjection() }) + private suspend fun toTypeConstructor(kt: KotlinType) = + GenericTypeConstructor( + DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), + kt.arguments.map { it.toProjection() }) - tailrec fun buildAncestryInformation( - supertypes: Collection, - level: Int = 0, - ancestryInformation: Set = emptySet() - ): Set { - if (supertypes.isEmpty()) return ancestryInformation - val (interfaces, superclass) = supertypes.partition { - (it.constructor.declarationDescriptor as ClassDescriptor).kind == ClassKind.INTERFACE - } + private tailrec suspend fun buildAncestryInformation( + supertypes: Collection, + level: Int = 0, + ancestryInformation: Set = emptySet() + ): Set { + if (supertypes.isEmpty()) return ancestryInformation + + val (interfaces, superclass) = supertypes.partition { + (it.constructor.declarationDescriptor as ClassDescriptor).kind == ClassKind.INTERFACE + } - val updated = ancestryInformation + AncestryLevel( + val updated = coroutineScope { + ancestryInformation + AncestryLevel( level, - superclass.map(::toTypeConstructor).singleOrNull(), - interfaces.map(::toTypeConstructor) - ) - return buildAncestryInformation( - supertypes = supertypes.flatMap { it.supertypes() }, - level = level + 1, - ancestryInformation = updated + superclass.parallelMap(::toTypeConstructor).singleOrNull(), + interfaces.parallelMap(::toTypeConstructor) ) } - return ClassInfo( - buildAncestryInformation(this.typeConstructor.supertypes.filterNot { it.isAnyOrNullableAny() }).sortedBy { it.level }, - resolveDescriptorData() + + return buildAncestryInformation( + supertypes = supertypes.flatMap { it.supertypes() }, + level = level + 1, + ancestryInformation = updated ) } - private fun TypeParameterDescriptor.toVariantTypeParameter() = + private suspend fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { + return coroutineScope { + ClassInfo( + buildAncestryInformation(this@resolveClassDescriptionData.typeConstructor.supertypes.filterNot { it.isAnyOrNullableAny() }).sortedBy { it.level }, + resolveDescriptorData() + ) + } + } + + private suspend fun TypeParameterDescriptor.toVariantTypeParameter() = DTypeParameter( variantTypeParameter( TypeParameter(DRI.from(this), name.identifier, annotations.getPresentableName()) @@ -636,11 +749,12 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll(additionalExtras().toSourceSetDependent().toAdditionalModifiers()) ) - private fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? = + private suspend fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? = map { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name") .safeAs()?.value?.drop(1)?.dropLast(1) // Dropping enclosing doublequotes because we don't want to have it in our custom signature serializer - private fun KotlinType.toBound(): Bound = when (this) { + private suspend fun KotlinType.toBound(): Bound = when (this) { + is DynamicType -> Dynamic is AbbreviatedType -> TypeAliased( abbreviation.toBound(), @@ -669,20 +783,23 @@ private class DokkaDescriptorVisitor( } } - private fun TypeProjection.toProjection(): Projection = + private suspend fun TypeProjection.toProjection(): Projection = if (isStarProjection) Star else formPossiblyVariant() - private fun TypeProjection.formPossiblyVariant(): Projection = type.toBound().wrapWithVariance(projectionKind) + private suspend fun TypeProjection.formPossiblyVariant(): Projection = + type.toBound().wrapWithVariance(projectionKind) - private fun TypeParameterDescriptor.variantTypeParameter(type: TypeParameter) = type.wrapWithVariance(variance) + private suspend fun TypeParameterDescriptor.variantTypeParameter(type: TypeParameter) = + type.wrapWithVariance(variance) - private fun T.wrapWithVariance(variance: org.jetbrains.kotlin.types.Variance) = when (variance) { - org.jetbrains.kotlin.types.Variance.INVARIANT -> Invariance(this) - org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Contravariance(this) - org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Covariance(this) - } + private fun T.wrapWithVariance(variance: org.jetbrains.kotlin.types.Variance) = + when (variance) { + org.jetbrains.kotlin.types.Variance.INVARIANT -> Invariance(this) + org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Contravariance(this) + org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Covariance(this) + } - private fun DeclarationDescriptor.getDocumentation() = findKDoc().let { + private suspend fun DeclarationDescriptor.getDocumentation() = findKDoc().let { MarkdownParser.parseFromKDocTag( kDocTag = it, externalDri = { link: String -> @@ -702,7 +819,7 @@ private class DokkaDescriptorVisitor( ) }.takeIf { it.children.isNotEmpty() } - private fun ClassDescriptor.companion(dri: DRIWithPlatformInfo): DObject? = companionObjectDescriptor?.let { + private suspend fun ClassDescriptor.companion(dri: DRIWithPlatformInfo): DObject? = companionObjectDescriptor?.let { objectDescriptor(it, dri) } @@ -756,9 +873,9 @@ private class DokkaDescriptorVisitor( ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { DescriptorUtils.isOverride(this) } ) - private fun Annotated.getAnnotations() = annotations.mapNotNull { it.toAnnotation() } + private suspend fun Annotated.getAnnotations() = annotations.parallelMapNotNull { it.toAnnotation() } - private fun ConstantValue<*>.toValue(): AnnotationParameterValue? = when (this) { + private suspend fun ConstantValue<*>.toValue(): AnnotationParameterValue? = when (this) { is ConstantsAnnotationValue -> value.toAnnotation()?.let { AnnotationValue(it) } is ConstantsArrayValue -> ArrayValue(value.mapNotNull { it.toValue() }) is ConstantsEnumValue -> EnumValue( @@ -782,7 +899,7 @@ private class DokkaDescriptorVisitor( else -> StringValue(toString()) } - private fun AnnotationDescriptor.toAnnotation(): Annotations.Annotation { + private suspend fun AnnotationDescriptor.toAnnotation(): Annotations.Annotation { return Annotations.Annotation( DRI.from(annotationClass as DeclarationDescriptor), allValueArguments.map { it.key.asString() to it.value.toValue() }.filter { @@ -792,7 +909,7 @@ private class DokkaDescriptorVisitor( ) } - private fun PropertyDescriptor.getAnnotationsWithBackingField(): List = + private suspend fun PropertyDescriptor.getAnnotationsWithBackingField(): List = getAnnotations() + (backingField?.getAnnotations() ?: emptyList()) private fun List.toAdditionalExtras() = mapNotNull { @@ -803,24 +920,25 @@ private class DokkaDescriptorVisitor( } } - private fun ValueParameterDescriptor.getDefaultValue(): String? = + private suspend fun ValueParameterDescriptor.getDefaultValue(): String? = (source as? KotlinSourceElement)?.psi?.children?.find { it is KtExpression }?.text - private fun PropertyDescriptor.getDefaultValue(): String? = + private suspend fun PropertyDescriptor.getDefaultValue(): String? = (source as? KotlinSourceElement)?.psi?.children?.find { it is KtConstantExpression }?.text - private fun ClassDescriptor.getAppliedConstructorParameters() = + private suspend fun ClassDescriptor.getAppliedConstructorParameters() = (source as PsiSourceElement).psi?.children?.flatMap { it.safeAs()?.initializersAsText().orEmpty() }.orEmpty() - private fun KtInitializerList.initializersAsText() = + private suspend fun KtInitializerList.initializersAsText() = initializers.firstIsInstanceOrNull() ?.getValueArgumentsInParentheses() ?.flatMap { it.childrenAsText() } .orEmpty() - private fun ValueArgument.childrenAsText() = this.safeAs()?.children?.map { it.text }.orEmpty() + private fun ValueArgument.childrenAsText() = + this.safeAs()?.children?.map { it.text }.orEmpty() private data class AncestryLevel( val level: Int, @@ -853,5 +971,4 @@ private class DokkaDescriptorVisitor( private fun ConstantsEnumValue.fullEnumEntryName() = "${this.enumClassId.relativeClassName.asString()}.${this.enumEntryName.identifier}" - } diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 39cb3c89..cbd02158 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -8,6 +8,8 @@ import com.intellij.psi.* import com.intellij.psi.impl.source.PsiClassReferenceType import com.intellij.psi.impl.source.PsiImmediateClassType import com.intellij.psi.javadoc.PsiDocComment +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.analysis.KotlinAnalysis import org.jetbrains.dokka.analysis.PsiDocumentableSource @@ -22,6 +24,9 @@ import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.dokka.utilities.parallelForEach +import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.dokka.utilities.parallelMapNotNull import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys @@ -44,42 +49,45 @@ class DefaultPsiToDocumentableTranslator( private val kotlinAnalysis: KotlinAnalysis ) : SourceToDocumentableTranslator { - override fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { + override suspend fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { + return coroutineScope { + fun isFileInSourceRoots(file: File): Boolean = + sourceSet.sourceRoots.any { root -> file.startsWith(root) } - fun isFileInSourceRoots(file: File): Boolean = - sourceSet.sourceRoots.any { root -> file.startsWith(root) } + val (environment, _) = kotlinAnalysis[sourceSet] - val (environment, _) = kotlinAnalysis[sourceSet] + val sourceRoots = environment.configuration.get(C