aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/transformers/documentables/utils
diff options
context:
space:
mode:
authorVadim Mishenev <vad-mishenev@yandex.ru>2022-08-29 13:27:43 +0300
committerGitHub <noreply@github.com>2022-08-29 13:27:43 +0300
commite68eea63f2affbacf69af041252bad4444fc812f (patch)
tree4acdb606b02d55a738690ff9796386da274fdef2 /plugins/base/src/main/kotlin/transformers/documentables/utils
parent34a8ae166e7220ddf8c3c42fab466234623501e7 (diff)
downloaddokka-e68eea63f2affbacf69af041252bad4444fc812f.tar.gz
dokka-e68eea63f2affbacf69af041252bad4444fc812f.tar.bz2
dokka-e68eea63f2affbacf69af041252bad4444fc812f.zip
Display inherited extensions (#2625)
Diffstat (limited to 'plugins/base/src/main/kotlin/transformers/documentables/utils')
-rw-r--r--plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt84
1 files changed, 84 insertions, 0 deletions
diff --git a/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt b/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt
new file mode 100644
index 00000000..d657fa32
--- /dev/null
+++ b/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt
@@ -0,0 +1,84 @@
+package org.jetbrains.dokka.base.transformers.documentables.utils
+
+import com.intellij.psi.PsiClass
+import kotlinx.coroutines.*
+import org.jetbrains.dokka.analysis.DescriptorDocumentableSource
+import org.jetbrains.dokka.analysis.PsiDocumentableSource
+import org.jetbrains.dokka.analysis.from
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.utilities.parallelForEach
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
+import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
+import java.util.concurrent.ConcurrentHashMap
+
+typealias Supertypes = List<DRI>
+typealias ClassHierarchy = SourceSetDependent<Map<DRI, Supertypes>>
+
+class FullClassHierarchyBuilder {
+ suspend operator fun invoke(original: DModule): ClassHierarchy = coroutineScope {
+ val map = original.sourceSets.associateWith { ConcurrentHashMap<DRI, List<DRI>>() }
+ original.packages.parallelForEach { visitDocumentable(it, map) }
+ map
+ }
+
+ private suspend fun collectSupertypesFromKotlinType(
+ driWithKType: Pair<DRI, KotlinType>,
+ supersMap: MutableMap<DRI, Supertypes>
+ ): Unit = coroutineScope {
+ val (dri, kotlinType) = driWithKType
+ val supertypes = kotlinType.immediateSupertypes().filterNot { it.isAnyOrNullableAny() }
+ val supertypesDriWithKType = supertypes.mapNotNull { supertype ->
+ supertype.constructor.declarationDescriptor?.let {
+ DRI.from(it) to supertype
+ }
+ }
+
+ if (supersMap[dri] == null) {
+ // another thread can rewrite the same value, but it isn't a problem
+ supersMap[dri] = supertypesDriWithKType.map { it.first }
+ supertypesDriWithKType.parallelForEach { collectSupertypesFromKotlinType(it, supersMap) }
+ }
+ }
+
+ private suspend fun collectSupertypesFromPsiClass(
+ driWithPsiClass: Pair<DRI, PsiClass>,
+ supersMap: MutableMap<DRI, Supertypes>
+ ): Unit = coroutineScope {
+ val (dri, psiClass) = driWithPsiClass
+ val supertypes = psiClass.superTypes.mapNotNull { it.resolve() }
+ .filterNot { it.qualifiedName == "java.lang.Object" }
+ val supertypesDriWithPsiClass = supertypes.map { DRI.from(it) to it }
+
+ if (supersMap[dri] == null) {
+ // another thread can rewrite the same value, but it isn't a problem
+ supersMap[dri] = supertypesDriWithPsiClass.map { it.first }
+ supertypesDriWithPsiClass.parallelForEach { collectSupertypesFromPsiClass(it, supersMap) }
+ }
+ }
+
+ private suspend fun visitDocumentable(
+ documentable: Documentable,
+ hierarchy: SourceSetDependent<MutableMap<DRI, List<DRI>>>
+ ): Unit = coroutineScope {
+ if (documentable is WithScope) {
+ documentable.classlikes.parallelForEach { visitDocumentable(it, hierarchy) }
+ }
+ if (documentable is DClasslike) {
+ // to build a full class graph, using supertypes from Documentable
+ // is not enough since it keeps only one level of hierarchy
+ documentable.sources.forEach { (sourceSet, source) ->
+ if (source is DescriptorDocumentableSource) {
+ val descriptor = source.descriptor as ClassDescriptor
+ val type = descriptor.defaultType
+ hierarchy[sourceSet]?.let { collectSupertypesFromKotlinType(documentable.dri to type, it) }
+ } else if (source is PsiDocumentableSource) {
+ val psi = source.psi as PsiClass
+ hierarchy[sourceSet]?.let { collectSupertypesFromPsiClass(documentable.dri to psi, it) }
+ }
+ }
+ }
+ }
+} \ No newline at end of file