From 785d741790f653d5c260f59c9d8875bbfde2dc07 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Wed, 12 Aug 2020 14:26:45 +0200 Subject: Fix generic supertypes to hold TypeParameters --- .../kotlin/signatures/KotlinSignatureProvider.kt | 14 ++-- .../main/kotlin/signatures/KotlinSignatureUtils.kt | 2 +- .../documentables/ExtensionExtractorTransformer.kt | 2 +- .../InheritorsExtractorTransformer.kt | 2 +- .../DefaultDescriptorToDocumentableTranslator.kt | 75 +++++++++++----------- .../psi/DefaultPsiToDocumentableTranslator.kt | 31 ++++----- 6 files changed, 65 insertions(+), 61 deletions(-) (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index 88879d81..bed8386d 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -15,6 +15,7 @@ import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.TextStyle import org.jetbrains.dokka.utilities.DokkaLogger +import java.lang.IllegalStateException import kotlin.text.Typography.nbsp class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider, @@ -182,9 +183,14 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog } } if (c is WithSupertypes) { - c.supertypes.filter { it.key == sourceSet }.map { (s, dris) -> - list(dris, prefix = " : ", sourceSets = setOf(s)) { - link(it.dri.sureClassNames, it.dri, sourceSets = setOf(s)) + c.supertypes.filter { it.key == sourceSet }.map { (s, typeConstructors) -> + list(typeConstructors, prefix = " : ", sourceSets = setOf(s)) { + link(it.typeConstructor.dri.sureClassNames, it.typeConstructor.dri, sourceSets = setOf(s)) + if ( it.typeConstructor.projections.isNotEmpty() ) { + list(it.typeConstructor.projections, prefix = "<", suffix = "> ") { + signatureForProjection(it) + } + } } } } @@ -313,7 +319,7 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog p: Projection, showFullyQualifiedName: Boolean = false ): Unit = when (p) { - is OtherParameter -> link(p.name, p.declarationDRI) + is TypeParameter -> link(p.name, p.declarationDRI) is TypeConstructor -> if (p.function) +funType(mainDRI.single(), mainSourcesetData, p) diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt index 0a10875a..193b41e1 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt @@ -35,7 +35,7 @@ object KotlinSignatureUtils : JvmSignatureUtils { val Bound.driOrNull: DRI? get() { return when (this) { - is OtherParameter -> this.declarationDRI + is TypeParameter -> this.declarationDRI is TypeConstructor -> this.dri is Nullable -> this.inner.driOrNull is PrimitiveJavaType -> this.dri diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt index 2da25d4b..6ce6e396 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt @@ -90,7 +90,7 @@ private fun Callable.asPairsWithReceiverDRIs(): Sequence> = // care about it since there is nowhere to put documentation of given extension. private fun Callable.findReceiverDRIs(bound: Bound): Sequence = when (bound) { is Nullable -> findReceiverDRIs(bound.inner) - is OtherParameter -> + is TypeParameter -> if (this is DFunction && bound.declarationDRI == this.dri) generics.find { it.name == bound.name }?.bounds?.asSequence()?.flatMap(::findReceiverDRIs).orEmpty() else diff --git a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt index 85256d51..181113ae 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt @@ -63,7 +63,7 @@ class InheritorsExtractorTransformer : DocumentableTransformer { private fun T.toInheritanceEntries() = (this as? WithSupertypes)?.let { - it.supertypes.map { (k, v) -> k to v.map { it.dri to dri } } + it.supertypes.map { (k, v) -> k to v.map { it.typeConstructor.dri to dri } } }.orEmpty() } diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index dac88768..9584d35a 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -11,6 +11,7 @@ import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.Nullable import org.jetbrains.dokka.model.TypeConstructor +import org.jetbrains.dokka.model.Variance import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.plugability.DokkaContext @@ -36,15 +37,13 @@ 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.descriptorUtil.getSuperClassNotAny -import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces 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 -import org.jetbrains.kotlin.types.DynamicType -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjection +import org.jetbrains.kotlin.types.* +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.nio.file.Paths @@ -557,28 +556,34 @@ private class DokkaDescriptorVisitor( getDocumentation()?.toSourceSetDependent() ?: emptyMap() private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { - tailrec fun buildInheritanceInformation( - inheritorClass: ClassDescriptor?, - interfaces: List, + + fun toTypeConstructor(kt: KotlinType) = + TypeConstructor(DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), kt.arguments.map { it.toProjection() }) + + tailrec fun buildAncestryInformation( + supertypes: Collection, level: Int = 0, - inheritanceInformation: Set = emptySet() - ): Set { - if (inheritorClass == null && interfaces.isEmpty()) return inheritanceInformation + ancestryInformation: Set = emptySet() + ): Set { + if (supertypes.isEmpty()) return ancestryInformation + + val (interfaces, superclass) = supertypes.partition { + (it.constructor.declarationDescriptor as ClassDescriptor).kind == ClassKind.INTERFACE + } - val updated = inheritanceInformation + InheritanceLevel( + val updated = ancestryInformation + AncestryLevel( level, - inheritorClass?.let { DRI.from(it) }, - interfaces.map { DRI.from(it) }) - val superInterfacesFromClass = inheritorClass?.getSuperInterfaces().orEmpty() - return buildInheritanceInformation( - inheritorClass = inheritorClass?.getSuperClassNotAny(), - interfaces = interfaces.flatMap { it.getSuperInterfaces() } + superInterfacesFromClass, + superclass.map(::toTypeConstructor).singleOrNull(), + interfaces.map(::toTypeConstructor) + ) + return buildAncestryInformation( + supertypes = supertypes.flatMap { it.supertypes() }, level = level + 1, - inheritanceInformation = updated + ancestryInformation = updated ) } return ClassInfo( - buildInheritanceInformation(getSuperClassNotAny(), getSuperInterfaces()).sortedBy { it.level }, + buildAncestryInformation(this.typeConstructor.supertypes.filterNot { it.isAnyOrNullableAny() }).sortedBy { it.level }, resolveDescriptorData() ) } @@ -597,7 +602,7 @@ private class DokkaDescriptorVisitor( private fun KotlinType.toBound(): Bound = when (this) { is DynamicType -> Dynamic else -> when (val ctor = constructor.declarationDescriptor) { - is TypeParameterDescriptor -> OtherParameter( + is TypeParameterDescriptor -> TypeParameter( declarationDRI = DRI.from(ctor.containingDeclaration).withPackageFallbackTo(fallbackPackageName()), name = ctor.name.asString() ) @@ -746,24 +751,16 @@ private class DokkaDescriptorVisitor( private fun ValueArgument.childrenAsText() = this.safeAs()?.children?.map { it.text }.orEmpty() - private data class InheritanceLevel(val level: Int, val superclass: DRI?, val interfaces: List) - - private data class ClassInfo( - val inheritance: List, - val docs: SourceSetDependent - ) { - val supertypes: List - get() = inheritance.firstOrNull { it.level == 0 }?.let { - listOfNotNull(it.superclass?.let { - DriWithKind( - it, - KotlinClassKindTypes.CLASS - ) - }) + it.interfaces.map { DriWithKind(it, KotlinClassKindTypes.INTERFACE) } - }.orEmpty() - - val allImplementedInterfaces: List - get() = inheritance.flatMap { it.interfaces }.distinct() + private data class AncestryLevel(val level: Int, val superclass: TypeConstructor?, val interfaces: List) + + private data class ClassInfo(val ancestry: List, val docs: SourceSetDependent){ + val supertypes: List + get() = ancestry.firstOrNull { it.level == 0 }?.let { + listOfNotNull(it.superclass?.let { TypeConstructorWithKind(it, KotlinClassKindTypes.CLASS) }) + it.interfaces.map { TypeConstructorWithKind(it, KotlinClassKindTypes.INTERFACE) } + }.orEmpty() + + val allImplementedInterfaces: List + get() = ancestry.flatMap { it.interfaces }.distinct() } private fun Visibility.toDokkaVisibility(): org.jetbrains.dokka.model.Visibility = when (this) { diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 0980083a..38a583d7 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -12,14 +12,11 @@ import org.jetbrains.dokka.analysis.KotlinAnalysis import org.jetbrains.dokka.analysis.PsiDocumentableSource import org.jetbrains.dokka.analysis.from import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.DriWithKind import org.jetbrains.dokka.links.nextTarget import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.doc.DocumentationLink import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.Param -import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator @@ -128,22 +125,27 @@ class DefaultPsiToDocumentableTranslator( fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = with(psi) { val dri = parent.withClass(name.toString()) - val inheritanceTree = mutableListOf() + val ancestryTree = mutableListOf() val superMethodsKeys = hashSetOf() val superMethods = mutableListOf>() methods.forEach { superMethodsKeys.add(it.hash) } fun parseSupertypes(superTypes: Array, level: Int = 0) { if (superTypes.isEmpty()) return - val parsedClasses = superTypes.filter { !it.shouldBeIgnored }.mapNotNull { - it.resolve()?.let { + val parsedClasses = superTypes.filter { !it.shouldBeIgnored }.mapNotNull { psi -> + psi.resolve()?.let { when { it.isInterface -> DRI.from(it) to JavaClassKindTypes.INTERFACE else -> DRI.from(it) to JavaClassKindTypes.CLASS + }?.let { + TypeConstructor( + it.first, + psi.parameters.map(::getProjection) + ) to it.second } } } val (classes, interfaces) = parsedClasses.partition { it.second == JavaClassKindTypes.CLASS } - inheritanceTree.add(AncestorLevel(level, classes.firstOrNull()?.first, interfaces.map { it.first })) + ancestryTree.add(AncestryLevel(level, classes.firstOrNull()?.first, interfaces.map { it.first })) superTypes.forEach { type -> (type as? PsiClassType)?.takeUnless { type.shouldBeIgnored }?.resolve()?.let { @@ -169,17 +171,16 @@ class DefaultPsiToDocumentableTranslator( val source = PsiDocumentableSource(this).toSourceSetDependent() val classlikes = innerClasses.map { parseClasslike(it, dri) } val visibility = getVisibility().toSourceSetDependent() - val ancestors = inheritanceTree.filter { it.level == 0 }.flatMap { + val ancestors = ancestryTree.filter { it.level == 0 }.flatMap { listOfNotNull(it.superclass?.let { - DriWithKind( - dri = it, + TypeConstructorWithKind( + typeConstructor = it , kind = JavaClassKindTypes.CLASS ) - }) + it.interfaces.map { DriWithKind(dri = it, kind = JavaClassKindTypes.INTERFACE) } + }) + it.interfaces.map { TypeConstructorWithKind(typeConstructor = it, kind = JavaClassKindTypes.INTERFACE) } }.toSourceSetDependent() val modifiers = getModifier().toSourceSetDependent() - val implementedInterfacesExtra = - ImplementedInterfaces(inheritanceTree.flatMap { it.interfaces }.distinct().toSourceSetDependent()) + val implementedInterfacesExtra = ImplementedInterfaces(ancestryTree.flatMap { it.interfaces }.distinct().toSourceSetDependent()) return when { isAnnotationType -> DAnnotation( @@ -353,7 +354,7 @@ class DefaultPsiToDocumentableTranslator( when { resolved.qualifiedName == "java.lang.Object" -> JavaObject resolved is PsiTypeParameter && resolved.owner != null -> - OtherParameter( + TypeParameter( declarationDRI = DRI.from(resolved.owner!!), name = resolved.name.orEmpty() ) @@ -491,5 +492,5 @@ class DefaultPsiToDocumentableTranslator( get() = getChildOfType()?.resolve() } - private data class AncestorLevel(val level: Int, val superclass: DRI?, val interfaces: List) + private data class AncestryLevel(val level: Int, val superclass: TypeConstructor?, val interfaces: List) } -- cgit