diff options
author | Andrzej Ratajczak <andrzej.ratajczak98@gmail.com> | 2020-08-12 14:26:45 +0200 |
---|---|---|
committer | Sebastian Sellmair <34319766+sellmair@users.noreply.github.com> | 2020-08-17 11:55:35 +0200 |
commit | 785d741790f653d5c260f59c9d8875bbfde2dc07 (patch) | |
tree | 9c5bac1028d4ddeffb9101e1776563f1882d5ccb /plugins/base | |
parent | 09004d828b5640b1471309f9e537ca64a28affd3 (diff) | |
download | dokka-785d741790f653d5c260f59c9d8875bbfde2dc07.tar.gz dokka-785d741790f653d5c260f59c9d8875bbfde2dc07.tar.bz2 dokka-785d741790f653d5c260f59c9d8875bbfde2dc07.zip |
Fix generic supertypes to hold TypeParameters
Diffstat (limited to 'plugins/base')
10 files changed, 76 insertions, 72 deletions
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<Pair<DRI, Callable>> = // care about it since there is nowhere to put documentation of given extension. private fun Callable.findReceiverDRIs(bound: Bound): Sequence<DRI> = 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 : Documentable> 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<ClassDescriptor>, + + fun toTypeConstructor(kt: KotlinType) = + TypeConstructor(DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), kt.arguments.map { it.toProjection() }) + + tailrec fun buildAncestryInformation( + supertypes: Collection<KotlinType>, level: Int = 0, - inheritanceInformation: Set<InheritanceLevel> = emptySet() - ): Set<InheritanceLevel> { - if (inheritorClass == null && interfaces.isEmpty()) return inheritanceInformation + ancestryInformation: Set<AncestryLevel> = emptySet() + ): Set<AncestryLevel> { + 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<KtValueArgument>()?.children?.map { it.text }.orEmpty() - private data class InheritanceLevel(val level: Int, val superclass: DRI?, val interfaces: List<DRI>) - - private data class ClassInfo( - val inheritance: List<InheritanceLevel>, - val docs: SourceSetDependent<DocumentationNode> - ) { - val supertypes: List<DriWithKind> - 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<DRI> - get() = inheritance.flatMap { it.interfaces }.distinct() + private data class AncestryLevel(val level: Int, val superclass: TypeConstructor?, val interfaces: List<TypeConstructor>) + + private data class ClassInfo(val ancestry: List<AncestryLevel>, val docs: SourceSetDependent<DocumentationNode>){ + val supertypes: List<TypeConstructorWithKind> + 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<TypeConstructor> + 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<AncestorLevel>() + val ancestryTree = mutableListOf<AncestryLevel>() val superMethodsKeys = hashSetOf<Int>() val superMethods = mutableListOf<Pair<PsiMethod, DRI>>() methods.forEach { superMethodsKeys.add(it.hash) } fun parseSupertypes(superTypes: Array<PsiClassType>, 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<PsiJavaCodeReferenceElement>()?.resolve() } - private data class AncestorLevel(val level: Int, val superclass: DRI?, val interfaces: List<DRI>) + private data class AncestryLevel(val level: Int, val superclass: TypeConstructor?, val interfaces: List<TypeConstructor>) } diff --git a/plugins/base/src/test/kotlin/basic/DRITest.kt b/plugins/base/src/test/kotlin/basic/DRITest.kt index 559a2dbf..353991ba 100644 --- a/plugins/base/src/test/kotlin/basic/DRITest.kt +++ b/plugins/base/src/test/kotlin/basic/DRITest.kt @@ -271,7 +271,7 @@ class DRITest : AbstractCoreTest() { val foo = sampleInner.children.first { it.name == "foo" } as MemberPageNode val documentable = foo.documentable as DFunction - assertEquals(sampleClass.dri.first().toString(), (documentable.type as OtherParameter).declarationDRI.toString()) + assertEquals(sampleClass.dri.first().toString(), (documentable.type as TypeParameter).declarationDRI.toString()) assertEquals(0, documentable.generics.size) } } diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt index 1bf55235..bb7bac2d 100644 --- a/plugins/base/src/test/kotlin/model/ClassesTest.kt +++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt @@ -221,7 +221,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class with((this / "f").cast<DFunction>()) { modifier.values.forEach { it equals Open } } - D.supertypes.flatMap { it.component2() }.firstOrNull()?.dri equals C.dri + D.supertypes.flatMap { it.component2() }.firstOrNull()?.typeConstructor?.dri equals C.dri } } } @@ -258,8 +258,8 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class modifier.values.forEach { it equals Final } } - D.supers.single().dri equals C.dri - E.supers.single().dri equals D.dri + D.supers.single().typeConstructor.dri equals C.dri + E.supers.single().typeConstructor.dri equals D.dri } } @@ -496,7 +496,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class """.trimIndent() ){ with((this / "classes" / "Tested").cast<DClass>()){ - extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower", "LowerImplInterface").sorted() + extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.dri.sureClassNames }?.sorted() equals listOf("Highest", "Lower", "LowerImplInterface").sorted() } } } @@ -510,7 +510,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class """.trimIndent() ) { with((this / "classes" / "Tested").cast<DClass>()) { - supertypes.entries.single().value.map { it.dri.sureClassNames }.single() equals "B" + supertypes.entries.single().value.map { it.typeConstructor.dri.sureClassNames }.single() equals "B" } } } @@ -526,7 +526,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class """.trimIndent() ){ with((this / "classes" / "Tested").cast<DClass>()) { - supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("B" to KotlinClassKindTypes.CLASS, "Y" to KotlinClassKindTypes.INTERFACE) + supertypes.entries.single().value.map { it.typeConstructor.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("B" to KotlinClassKindTypes.CLASS, "Y" to KotlinClassKindTypes.INTERFACE) } } } diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt index 237131d3..4e9b9de4 100644 --- a/plugins/base/src/test/kotlin/model/JavaTest.kt +++ b/plugins/base/src/test/kotlin/model/JavaTest.kt @@ -49,7 +49,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |class Tested extends Extendable implements Lower { } """){ with((this / "java" / "Tested").cast<DClass>()){ - extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower").sorted() + extra[ImplementedInterfaces]?.interfaces?.entries?.single()?.value?.map { it.dri.sureClassNames }?.sorted() equals listOf("Highest", "Lower").sorted() } } } @@ -63,7 +63,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |class Tested extends Extendable implements Lower { } """){ with((this / "java" / "Tested").cast<DClass>()) { - supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("Extendable" to JavaClassKindTypes.CLASS, "Lower" to JavaClassKindTypes.INTERFACE) + supertypes.entries.single().value.map { it.typeConstructor.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("Extendable" to JavaClassKindTypes.CLASS, "Lower" to JavaClassKindTypes.INTERFACE) } } } @@ -98,7 +98,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { with((this / "java" / "Foo").cast<DClass>()) { val sups = listOf("Exception", "Cloneable") assertTrue( - sups.all { s -> supertypes.values.flatten().any { it.dri.classNames == s } }) + sups.all { s -> supertypes.values.flatten().any { it.typeConstructor.dri.classNames == s } }) "Foo must extend ${sups.joinToString(", ")}" } } diff --git a/plugins/base/src/test/kotlin/utils/TestUtils.kt b/plugins/base/src/test/kotlin/utils/TestUtils.kt index bd0e1fe2..5183972a 100644 --- a/plugins/base/src/test/kotlin/utils/TestUtils.kt +++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt @@ -69,7 +69,7 @@ val DClass.supers val Bound.name: String? get() = when (this) { is Nullable -> inner.name - is OtherParameter -> name + is TypeParameter -> name is PrimitiveJavaType -> name is TypeConstructor -> dri.classNames is JavaObject -> "Object" |