Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Ancestry Graphs #2326

Merged
merged 1 commit into from Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions core/api/core.api
Expand Up @@ -667,6 +667,22 @@ public final class org/jetbrains/dokka/model/AdditionalModifiers$Companion : org
public fun mergeStrategyFor (Lorg/jetbrains/dokka/model/AdditionalModifiers;Lorg/jetbrains/dokka/model/AdditionalModifiers;)Lorg/jetbrains/dokka/model/properties/MergeStrategy;
}

public final class org/jetbrains/dokka/model/AncestryNode {
public fun <init> (Lorg/jetbrains/dokka/model/TypeConstructor;Lorg/jetbrains/dokka/model/AncestryNode;Ljava/util/List;)V
public final fun allImplementedInterfaces ()Ljava/util/List;
public final fun component1 ()Lorg/jetbrains/dokka/model/TypeConstructor;
public final fun component2 ()Lorg/jetbrains/dokka/model/AncestryNode;
public final fun component3 ()Ljava/util/List;
public final fun copy (Lorg/jetbrains/dokka/model/TypeConstructor;Lorg/jetbrains/dokka/model/AncestryNode;Ljava/util/List;)Lorg/jetbrains/dokka/model/AncestryNode;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/model/AncestryNode;Lorg/jetbrains/dokka/model/TypeConstructor;Lorg/jetbrains/dokka/model/AncestryNode;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/AncestryNode;
public fun equals (Ljava/lang/Object;)Z
public final fun getInterfaces ()Ljava/util/List;
public final fun getSuperclass ()Lorg/jetbrains/dokka/model/AncestryNode;
public final fun getTypeConstructor ()Lorg/jetbrains/dokka/model/TypeConstructor;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract class org/jetbrains/dokka/model/AnnotationParameterValue {
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/kotlin/model/additionalExtras.kt
Expand Up @@ -123,4 +123,4 @@ data class ConstructorValues(val values: SourceSetDependent<List<Expression>>) :
}

override val key: ExtraProperty.Key<DEnumEntry, ConstructorValues> = ConstructorValues
}
}
14 changes: 14 additions & 0 deletions core/src/main/kotlin/model/ancestryNode.kt
@@ -0,0 +1,14 @@
package org.jetbrains.dokka.model

data class AncestryNode(
val typeConstructor: TypeConstructor,
val superclass: AncestryNode?,
val interfaces: List<AncestryNode>,
) {
fun allImplementedInterfaces(): List<TypeConstructor> {
fun traverseInterfaces(ancestry: AncestryNode): List<TypeConstructor> =
ancestry.interfaces.flatMap { listOf(it.typeConstructor) + traverseInterfaces(it) } +
(ancestry.superclass?.let(::traverseInterfaces) ?: emptyList())
return traverseInterfaces(this).distinct()
}
}
Expand Up @@ -13,15 +13,14 @@ import org.jetbrains.dokka.analysis.KotlinAnalysis
import org.jetbrains.dokka.analysis.from
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.parsers.MarkdownParser
import org.jetbrains.dokka.base.translators.isDirectlyAnException
import org.jetbrains.dokka.base.translators.typeConstructorsBeingExceptions
import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser
import org.jetbrains.dokka.base.translators.unquotedValue
import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.links.Callable
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.AnnotationTarget
import org.jetbrains.dokka.model.Nullable
import org.jetbrains.dokka.model.TypeConstructor
import org.jetbrains.dokka.model.doc.*
import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.plugability.DokkaContext
Expand Down Expand Up @@ -215,8 +214,8 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()),
info.exceptionsInSupertypes?.let { ExceptionInSupertypes(it.toSourceSetDependent()) },
ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()),
info.ancestry.exceptionInSupertypesOrNull()
)
)
}
Expand Down Expand Up @@ -253,8 +252,8 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()),
info.exceptionsInSupertypes?.let { ExceptionInSupertypes(it.toSourceSetDependent()) },
ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()),
info.ancestry.exceptionInSupertypesOrNull()
)
)
}
Expand Down Expand Up @@ -298,7 +297,7 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent())
ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent())
)
)
}
Expand Down Expand Up @@ -420,8 +419,8 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll<DClass>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()),
info.exceptionsInSupertypes?.let { ExceptionInSupertypes(it.toSourceSetDependent()) },
ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()),
info.ancestry.exceptionInSupertypesOrNull()
)
)
}
Expand Down Expand Up @@ -664,8 +663,10 @@ private class DokkaDescriptorVisitor(
with(descriptor) {
coroutineScope {
val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } }
val info = buildAncestryInformation(listOf(underlyingType)).sortedBy { it.level }

val info = buildAncestryInformation(defaultType).copy(
superclass = buildAncestryInformation(underlyingType),
interfaces = emptyList()
)
DTypeAlias(
dri = DRI.from(this@with),
name = name.asString(),
Expand All @@ -678,8 +679,7 @@ private class DokkaDescriptorVisitor(
generics = generics.await(),
extra = PropertyContainer.withAll(
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
info.exceptionsInSupertypes()?.takeIf { it.isNotEmpty() }
?.let { ExceptionInSupertypes(it.toSourceSetDependent()) },
info.exceptionInSupertypesOrNull(),
)
)
}
Expand Down Expand Up @@ -759,41 +759,31 @@ private class DokkaDescriptorVisitor(
DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor),
kt.arguments.map { it.toProjection() })


private tailrec suspend fun buildAncestryInformation(
supertypes: Collection<KotlinType>,
level: Int = 0,
ancestryInformation: Set<AncestryLevel> = emptySet()
): Set<AncestryLevel> {
if (supertypes.isEmpty()) return ancestryInformation

val (interfaces, superclass) = supertypes
private suspend fun buildAncestryInformation(
kotlinType: KotlinType
): AncestryNode {
val (interfaces, superclass) = kotlinType.immediateSupertypes().filterNot { it.isAnyOrNullableAny() }
.partition {
val declaration = it.constructor.declarationDescriptor
val descriptor = declaration as? ClassDescriptor
?: (declaration as? TypeAliasDescriptor)?.underlyingType?.constructor?.declarationDescriptor as? ClassDescriptor
descriptor?.kind == ClassKind.INTERFACE
}

val updated = coroutineScope {
ancestryInformation + AncestryLevel(
level,
superclass.parallelMap(::toTypeConstructor).singleOrNull(),
interfaces.parallelMap(::toTypeConstructor)
return coroutineScope {
AncestryNode(
typeConstructor = toTypeConstructor(kotlinType),
superclass = superclass.parallelMap(::buildAncestryInformation).singleOrNull(),
interfaces = interfaces.parallelMap(::buildAncestryInformation)
)
}

return buildAncestryInformation(
supertypes = supertypes.flatMap { it.immediateSupertypes() },
level = level + 1,
ancestryInformation = updated
)
}


private suspend fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo {
return coroutineScope {
ClassInfo(
buildAncestryInformation(this@resolveClassDescriptionData.typeConstructor.supertypes.filterNot { it.isAnyOrNullableAny() }).sortedBy { it.level },
buildAncestryInformation(this@resolveClassDescriptionData.defaultType),
resolveDescriptorData()
)
}
Expand Down Expand Up @@ -1050,22 +1040,16 @@ private class DokkaDescriptorVisitor(
else -> node?.text?.let { ComplexExpression(it) }
}

private data class ClassInfo(val ancestry: List<AncestryLevel>, val docs: SourceSetDependent<DocumentationNode>) {
private data class ClassInfo(val ancestry: AncestryNode, val docs: SourceSetDependent<DocumentationNode>) {
val supertypes: List<TypeConstructorWithKind>
get() = ancestry.firstOrNull { it.level == 0 }?.let {
listOfNotNull(it.superclass?.let {
get() = listOfNotNull(ancestry.superclass?.let {
it.typeConstructor.let {
TypeConstructorWithKind(
it,
KotlinClassKindTypes.CLASS
)
}) + it.interfaces.map { TypeConstructorWithKind(it, KotlinClassKindTypes.INTERFACE) }
}.orEmpty()

val allImplementedInterfaces: List<TypeConstructor>
get() = ancestry.flatMap { it.interfaces }.distinct()

val exceptionsInSupertypes: List<TypeConstructor>?
get() = ancestry.exceptionsInSupertypes()
}
}) + ancestry.interfaces.map { TypeConstructorWithKind(it.typeConstructor, KotlinClassKindTypes.INTERFACE) }
}

private fun DescriptorVisibility.toDokkaVisibility(): org.jetbrains.dokka.model.Visibility = when (this.delegate) {
Expand Down Expand Up @@ -1093,13 +1077,8 @@ private class DokkaDescriptorVisitor(
kind == CallableMemberDescriptor.Kind.SYNTHESIZED ||
containingDeclaration.fqNameOrNull()?.asString()
?.let { it == "kotlin.Any" || it == "kotlin.Enum" || it == "java.lang.Enum" || it == "java.lang.Object" } == true
}

private data class AncestryLevel(
val level: Int,
val superclass: TypeConstructor?,
val interfaces: List<TypeConstructor>
)
private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? =
typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() }?.let { ExceptionInSupertypes(it.toSourceSetDependent()) }
}

private fun List<AncestryLevel>.exceptionsInSupertypes(): List<TypeConstructor>? =
mapNotNull { it.superclass }.filter { type -> type.dri.isDirectlyAnException() }.takeIf { it.isNotEmpty() }
9 changes: 9 additions & 0 deletions plugins/base/src/main/kotlin/translators/isException.kt
@@ -1,6 +1,15 @@
package org.jetbrains.dokka.base.translators

import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.AncestryNode
import org.jetbrains.dokka.model.TypeConstructor

internal fun AncestryNode.typeConstructorsBeingExceptions(): List<TypeConstructor> {
fun traverseSupertypes(ancestry: AncestryNode): List<TypeConstructor> =
listOf(ancestry.typeConstructor) + (ancestry.superclass?.let(::traverseSupertypes) ?: emptyList())

return superclass?.let(::traverseSupertypes)?.filter { type -> type.dri.isDirectlyAnException() } ?: emptyList()
}

internal fun DRI.isDirectlyAnException(): Boolean =
toString().let { stringed ->
Expand Down