aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/kotlin/CoreExtensions.kt4
-rw-r--r--core/src/main/kotlin/links/DRI.kt3
-rw-r--r--core/src/main/kotlin/model/Documentable.kt15
-rw-r--r--core/src/main/kotlin/model/SignatureProvider.kt7
-rw-r--r--plugins/base/src/main/kotlin/providers/KotlinSignatureProvider.kt113
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt35
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt2
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt10
8 files changed, 163 insertions, 26 deletions
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt
index dd6eab1b..6a1af187 100644
--- a/core/src/main/kotlin/CoreExtensions.kt
+++ b/core/src/main/kotlin/CoreExtensions.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka
+import org.jetbrains.dokka.model.SignatureProvider
import org.jetbrains.dokka.plugability.ExtensionPoint
import org.jetbrains.dokka.renderers.Renderer
import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentableTranslator
@@ -18,8 +19,9 @@ object CoreExtensions {
val documentableToPageTranslator by coreExtension<DocumentableToPageTranslator>()
val pageTransformer by coreExtension<PageTransformer>()
val renderer by coreExtension<Renderer>()
+ val signatureProvider by coreExtension<SignatureProvider>()
- private fun <T: Any> coreExtension() = object {
+ private fun <T : Any> coreExtension() = object {
operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy<ExtensionPoint<T>> =
lazy { ExtensionPoint<T>(thisRef::class.qualifiedName!!, property.name) }
}
diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt
index 791d2b5e..57ac96e5 100644
--- a/core/src/main/kotlin/links/DRI.kt
+++ b/core/src/main/kotlin/links/DRI.kt
@@ -68,6 +68,9 @@ val DRI.parent: DRI
else -> DRI.topLevel
}
+val DRI.sureClassNames
+ get() = classNames ?: throw IllegalStateException("Malformed DRI. It requires classNames in this context.")
+
data class Callable(
val name: String,
val receiver: TypeReference? = null,
diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt
index c16f8a87..4190edc3 100644
--- a/core/src/main/kotlin/model/Documentable.kt
+++ b/core/src/main/kotlin/model/Documentable.kt
@@ -315,7 +315,7 @@ data class TypeParameter(
override val dri: DRI,
override val name: String,
override val documentation: PlatformDependent<DocumentationNode>,
- val bounds: List<Projection>,
+ val bounds: List<Bound>,
override val platformData: List<PlatformData>,
override val extra: PropertyContainer<TypeParameter> = PropertyContainer.empty()
) : Documentable(), WithExtraProperties<TypeParameter> {
@@ -325,11 +325,14 @@ data class TypeParameter(
override fun withNewExtras(newExtras: PropertyContainer<TypeParameter>) = copy(extra = newExtras)
}
-sealed class Projection {
- data class OtherParameter(val name: String) : Projection()
- object Star : Projection()
- data class TypeConstructor(val dri: DRI, val projections: List<Projection>) : Projection()
- data class Nullable(val inner: Projection) : Projection()
+sealed class Projection
+sealed class Bound : Projection()
+data class OtherParameter(val name: String) : Bound()
+object Star : Projection()
+data class TypeConstructor(val dri: DRI, val projections: List<Projection>) : Bound()
+data class Nullable(val inner: Bound) : Bound()
+data class Variance(val kind: Kind, val inner: Bound): Projection() {
+ enum class Kind { In, Out }
}
enum class ExtraModifiers {
diff --git a/core/src/main/kotlin/model/SignatureProvider.kt b/core/src/main/kotlin/model/SignatureProvider.kt
new file mode 100644
index 00000000..2df0f4b6
--- /dev/null
+++ b/core/src/main/kotlin/model/SignatureProvider.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.model
+
+import org.jetbrains.dokka.pages.ContentNode
+
+interface SignatureProvider {
+ fun signature(documentable: Documentable): List<ContentNode>
+} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/providers/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/providers/KotlinSignatureProvider.kt
new file mode 100644
index 00000000..efee39fd
--- /dev/null
+++ b/plugins/base/src/main/kotlin/providers/KotlinSignatureProvider.kt
@@ -0,0 +1,113 @@
+package org.jetbrains.dokka.base.providers
+
+import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.sureClassNames
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.Enum
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.pages.ContentKind
+import org.jetbrains.dokka.pages.ContentNode
+import org.jetbrains.dokka.pages.PlatformData
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider {
+ private val contentBuilder = PageContentBuilder(ctcc, logger)
+
+ override fun signature(documentable: Documentable): List<ContentNode> = when (documentable) {
+ is Function -> signature(documentable)
+ is Classlike -> signature(documentable)
+ else -> throw NotImplementedError(
+ "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}"
+ )
+ }
+
+ private fun signature(f: Function) = f.platformData.map { signature(f, it) }.distinct()
+
+ private fun signature(c: Classlike) = c.platformData.map { signature(c, it) }.distinct()
+
+ private fun signature(c: Classlike, platform: PlatformData) = contentBuilder.contentFor(c, ContentKind.Symbol) {
+ text(c.visibility[platform]?.externalDisplayName ?: "")
+ if (c is Class) {
+ text(c.modifier.toString())
+ }
+ when (c) {
+ is Class -> text(" class ")
+ is Interface -> text(" interface ")
+ is Enum -> text(" enum ")
+ is Object -> text(" object ")
+ }
+ text(c.name!!)
+ if (c is WithSupertypes) {
+ list(c.supertypes.getValue(platform), prefix = " : ") {
+ link(it.sureClassNames, it)
+ }
+ }
+ }
+
+ private fun signature(f: Function, platform: PlatformData) = contentBuilder.contentFor(f, ContentKind.Symbol) {
+ text(f.visibility[platform]?.externalDisplayName ?: "")
+ text(f.modifier.toString())
+ text(" fun ")
+ f.receiver?.also {
+ type(it.type)
+ text(".")
+ }
+ link(f.name, f.dri)
+ val generics = f.generics.filterOnPlatform(platform)
+ if (generics.isNotEmpty()) {
+ text("<")
+ generics.forEach {
+ signature(it)
+ }
+ text(">")
+ }
+ text("(")
+ list(f.parameters.filterOnPlatform(platform)) {
+ link(it.name!!, it.dri)
+ text(": ")
+ type(it.type)
+ }
+ text(")")
+ val returnType = f.type
+ if (!f.isConstructor && returnType.constructorFqName != Unit::class.qualifiedName) {
+ text(": ")
+
+ type(returnType)
+ }
+ }
+
+ private fun signature(t: TypeParameter) = contentBuilder.contentFor(t, ContentKind.Symbol) {
+ link(t.name, t.dri)
+ if (t.bounds.isNotEmpty()) {
+ text("<")
+ t.bounds.forEach {
+ signature(it, t.dri, t.platformData)
+ }
+ text(">")
+ }
+ }
+
+ private fun signature(p: Projection, dri: DRI, platforms: List<PlatformData>): List<ContentNode> = when (p) {
+ is OtherParameter -> contentBuilder.contentFor(dri, platforms.toSet()) { text(p.name) }.children
+
+ is TypeConstructor -> contentBuilder.contentFor(dri, platforms.toSet()) {
+ link(p.dri.classNames.orEmpty(), p.dri)
+ }.children + p.projections.flatMap { signature(it, dri, platforms) }
+
+ is Variance -> contentBuilder.contentFor(dri, platforms.toSet()) {
+ text(p.kind.toString() + " ")
+ }.children + signature(p.inner, dri, platforms)
+
+ is Star -> contentBuilder.contentFor(dri, platforms.toSet()) { text("*") }.children
+
+ is Nullable -> signature(p.inner, dri, platforms) + contentBuilder.contentFor(
+ dri,
+ platforms.toSet()
+ ) { text("?") }.children
+ }
+
+ private fun <T : Documentable> Collection<T>.filterOnPlatform(platformData: PlatformData) =
+ this.filter { it.platformData.contains(platformData) }
+} \ 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 83d3d178..ad28a4bc 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -18,8 +18,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
@@ -31,6 +29,9 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjection
+import org.jetbrains.dokka.model.Variance
+import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf.fqName
+import org.jetbrains.kotlin.idea.kdoc.findKDoc
class DefaultDescriptorToDocumentableTranslator(
private val context: DokkaContext
@@ -134,7 +135,7 @@ open class DokkaDescriptorVisitor( // TODO: close this class and make it private
)
}
- fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Enum {
+ private fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Enum {
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val info = descriptor.resolveClassDescriptionData(platformData)
@@ -157,7 +158,7 @@ open class DokkaDescriptorVisitor( // TODO: close this class and make it private
)
}
- fun enumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): EnumEntry {
+ private fun enumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): EnumEntry {
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
@@ -173,7 +174,7 @@ open class DokkaDescriptorVisitor( // TODO: close this class and make it private
)
}
- fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Class {
+ private fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Class {
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val info = descriptor.resolveClassDescriptionData(platformData)
@@ -395,26 +396,34 @@ open class DokkaDescriptorVisitor( // TODO: close this class and make it private
DRI.from(this),
fqNameSafe.asString(),
PlatformDependent.from(platformData, getDocumentation()),
- upperBounds.map { it.toProjection() },
+ upperBounds.map { it.toBound() },
listOf(platformData),
extra = additionalExtras()
)
- private fun KotlinType.toProjection(): Projection = when (constructor.declarationDescriptor) {
- is TypeParameterDescriptor -> Projection.OtherParameter(fqName.toString()).let {
- if (isMarkedNullable) Projection.Nullable(it) else it
+ private fun KotlinType.toBound(): Bound = when (constructor.declarationDescriptor) {
+ is TypeParameterDescriptor -> OtherParameter(fqName.toString()).let {
+ if (isMarkedNullable) Nullable(it) else it
}
- else -> Projection.TypeConstructor(
+ else -> TypeConstructor(
DRI.from(constructor.declarationDescriptor!!), // TODO: remove '!!'
arguments.map { it.toProjection() }
)
}
private fun TypeProjection.toProjection(): Projection =
- if (isStarProjection) Projection.Star else fromPossiblyNullable(type)
+ if (isStarProjection) Star else formPossiblyVariant()
+
+ private fun TypeProjection.formPossiblyVariant(): Projection = type.fromPossiblyNullable().let {
+ when (projectionKind) {
+ org.jetbrains.kotlin.types.Variance.INVARIANT -> it
+ org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance(Variance.Kind.In, it)
+ org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance(Variance.Kind.Out, it)
+ }
+ }
- private fun fromPossiblyNullable(t: KotlinType): Projection =
- t.toProjection().let { if (t.isMarkedNullable) Projection.Nullable(it) else it }
+ private fun KotlinType.fromPossiblyNullable(): Bound =
+ toBound().let { if (isMarkedNullable) Nullable(it) else it }
private fun DeclarationDescriptor.getDocumentation() = findKDoc().let {
MarkdownParser(resolutionFacade, this).parseFromKDocTag(it)
diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
index 9d153a19..176aa87f 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
@@ -160,7 +160,7 @@ open class PageContentBuilder(
elements: List<T>,
prefix: String = "",
suffix: String = "",
- separator: String = ",",
+ separator: String = ", ",
operation: DocumentableContentBuilder.(T) -> Unit
) {
if (elements.isNotEmpty()) {
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
index 3e95865e..4b4cf8db 100644
--- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
@@ -249,10 +249,10 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
}
private fun PsiTypeParameterListOwner.mapTypeParameters(dri: DRI): List<TypeParameter> {
- fun mapProjections(bounds: Array<JvmReferenceType>) =
- if (bounds.isEmpty()) listOf(Projection.Star) else bounds.mapNotNull {
- (it as PsiClassType).let { classType ->
- Projection.Nullable(Projection.TypeConstructor(classType.resolve()!!.toDRI(), emptyList()))
+ fun mapBounds(bounds: Array<JvmReferenceType>): List<Bound> =
+ if (bounds.isEmpty()) emptyList() else bounds.mapNotNull {
+ (it as? PsiClassType)?.let { classType ->
+ Nullable(TypeConstructor(classType.resolve()!!.toDRI(), emptyList()))
}
}
return typeParameters.mapIndexed { index, type ->
@@ -260,7 +260,7 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
dri.copy(genericTarget = index),
type.name.orEmpty(),
javadocParser.parseDocumentation(type).toPlatformDependant(),
- mapProjections(type.bounds),
+ mapBounds(type.bounds),
listOf(platformData)
)
}