Skip to content

Commit

Permalink
Add better handling of functional types in rendered output
Browse files Browse the repository at this point in the history
  • Loading branch information
BarkingBad authored and Kordyjan committed Sep 28, 2020
1 parent 2274d92 commit 64ec7ad
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 42 deletions.
40 changes: 26 additions & 14 deletions core/src/main/kotlin/model/Documentable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,13 @@ data class DTypeParameter(
constructor(
dri: DRI,
name: String,
presentableName: String?,
documentation: SourceSetDependent<DocumentationNode>,
expectPresentInSet: DokkaSourceSet?,
bounds: List<Bound>,
sourceSets: Set<DokkaSourceSet>,
extra: PropertyContainer<DTypeParameter> = PropertyContainer.empty()
) : this(Invariance(TypeParameter(dri, name)), documentation, expectPresentInSet, bounds, sourceSets, extra)
) : this(Invariance(TypeParameter(dri, name, presentableName)), documentation, expectPresentInSet, bounds, sourceSets, extra)

override val dri: DRI by variantTypeParameter.inner::dri
override val name: String by variantTypeParameter.inner::name
Expand Down Expand Up @@ -376,13 +377,28 @@ data class DTypeAlias(

sealed class Projection
sealed class Bound : Projection()
data class TypeParameter(val dri: DRI, val name: String) : Bound()
data class TypeParameter(val dri: DRI, val name: String, val presentableName: String? = null) : Bound()
object Star : Projection()
data class TypeConstructor(
val dri: DRI,
val projections: List<Projection>,
val modifier: FunctionModifiers = FunctionModifiers.NONE
) : Bound()

sealed class TypeConstructor : Bound() {
abstract val dri: DRI
abstract val projections: List<Projection>
abstract val presentableName: String?
}

data class GenericTypeConstructor(
override val dri: DRI,
override val projections: List<Projection>,
override val presentableName: String? = null
) : TypeConstructor()

data class FunctionalTypeConstructor(
override val dri: DRI,
override val projections: List<Projection>,
val isExtensionFunction: Boolean = false,
val isSuspendable: Boolean = false,
override val presentableName: String? = null
) : TypeConstructor()

data class Nullable(val inner: Bound) : Bound()

Expand All @@ -406,14 +422,10 @@ object JavaObject : Bound()
object Dynamic : Bound()
data class UnresolvedBound(val name: String) : Bound()

enum class FunctionModifiers {
NONE, FUNCTION, EXTENSION
}

fun Variance<TypeParameter>.withDri(dri: DRI) = when(this) {
is Contravariance -> Contravariance(TypeParameter(dri, inner.name))
is Covariance -> Covariance(TypeParameter(dri, inner.name))
is Invariance -> Invariance(TypeParameter(dri, inner.name))
is Contravariance -> Contravariance(TypeParameter(dri, inner.name, inner.presentableName))
is Covariance -> Covariance(TypeParameter(dri, inner.name, inner.presentableName))
is Invariance -> Invariance(TypeParameter(dri, inner.name, inner.presentableName))
}

private fun String.shorten(maxLength: Int) = lineSequence().first().let {
Expand Down
28 changes: 14 additions & 14 deletions plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,15 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
when (p) {
is TypeParameter -> link(p.name, p.dri)

is TypeConstructor -> if (p.function)
is FunctionalTypeConstructor ->
+funType(mainDRI.single(), mainSourcesetData, p)
else

is GenericTypeConstructor ->
group(styles = emptySet()) {
val linkText = if (showFullyQualifiedName && p.dri.packageName != null) {
"${p.dri.packageName}.${p.dri.classNames.orEmpty()}"
} else p.dri.classNames.orEmpty()

if (p.presentableName != null) text(p.presentableName + ": ")
link(linkText, p.dri)
list(p.projections, prefix = "<", suffix = ">") {
signatureForProjection(it, showFullyQualifiedName)
Expand All @@ -357,14 +358,18 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
is UnresolvedBound -> text(p.name)
}

private fun funType(dri: DRI, sourceSets: Set<DokkaSourceSet>, type: TypeConstructor) =
private fun funType(dri: DRI, sourceSets: Set<DokkaSourceSet>, type: FunctionalTypeConstructor) =
contentBuilder.contentFor(dri, sourceSets, ContentKind.Main) {
if (type.extension) {

if (type.presentableName != null) text(type.presentableName + ": ")
if (type.isSuspendable) text("suspend ")

if (type.isExtensionFunction) {
signatureForProjection(type.projections.first())
text(".")
}

val args = if (type.extension)
val args = if (type.isExtensionFunction)
type.projections.drop(1)
else
type.projections
Expand All @@ -379,16 +384,11 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog
}
}

private fun PrimitiveJavaType.translateToKotlin() = TypeConstructor(
private fun PrimitiveJavaType.translateToKotlin() = GenericTypeConstructor(
dri = dri,
projections = emptyList()
projections = emptyList(),
presentableName = null
)

private val DTypeParameter.nontrivialBounds: List<Bound>
get() = bounds.filterNot { it is Nullable && it.inner.driOrNull == DriOfAny }

val TypeConstructor.function
get() = modifier == FunctionModifiers.FUNCTION || modifier == FunctionModifiers.EXTENSION

val TypeConstructor.extension
get() = modifier == FunctionModifiers.EXTENSION
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
import org.jetbrains.kotlin.codegen.isJvmStaticInObjectOrClassOrInterface
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
Expand Down Expand Up @@ -586,7 +589,7 @@ private class DokkaDescriptorVisitor(
private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo {

fun toTypeConstructor(kt: KotlinType) =
TypeConstructor(
GenericTypeConstructor(
DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor),
kt.arguments.map { it.toProjection() })

Expand Down Expand Up @@ -621,7 +624,7 @@ private class DokkaDescriptorVisitor(
private fun TypeParameterDescriptor.toVariantTypeParameter() =
DTypeParameter(
variantTypeParameter(
TypeParameter(DRI.from(this), name.identifier)
TypeParameter(DRI.from(this), name.identifier, annotations.getPresentableName())
),
resolveDescriptorData(),
null,
Expand All @@ -630,6 +633,10 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(additionalExtras().toSourceSetDependent().toAdditionalModifiers())
)

private fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? =
map { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name")
.safeAs<StringValue>()?.value?.drop(1)?.dropLast(1) // Dropping enclosing doublequotes because we don't want to have it in our custom signature serializer

private fun KotlinType.toBound(): Bound = when (this) {
is DynamicType -> Dynamic
is AbbreviatedType -> TypeAliased(
Expand All @@ -639,14 +646,20 @@ private class DokkaDescriptorVisitor(
else -> when (val ctor = constructor.declarationDescriptor) {
is TypeParameterDescriptor -> TypeParameter(
dri = DRI.from(ctor),
name = ctor.name.asString()
name = ctor.name.asString(),
presentableName = annotations.getPresentableName()
)
is FunctionClassDescriptor -> FunctionalTypeConstructor(
DRI.from(ctor),
arguments.map { it.toProjection() },
isExtensionFunction = isExtensionFunctionType || isBuiltinExtensionFunctionalType,
isSuspendable = isSuspendFunctionTypeOrSubtype,
presentableName = annotations.getPresentableName()
)
else -> TypeConstructor(
else -> GenericTypeConstructor(
DRI.from(ctor!!), // TODO: remove '!!'
arguments.map { it.toProjection() },
if (isExtensionFunctionType) FunctionModifiers.EXTENSION
else if (isFunctionType) FunctionModifiers.FUNCTION
else FunctionModifiers.NONE
annotations.getPresentableName()
)
}.let {
if (isMarkedNullable) Nullable(it) else it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
Expand Down Expand Up @@ -139,7 +141,7 @@ class DefaultPsiToDocumentableTranslator(
psiClass.isInterface -> DRI.from(psiClass) to JavaClassKindTypes.INTERFACE
else -> DRI.from(psiClass) to JavaClassKindTypes.CLASS
}
TypeConstructor(
GenericTypeConstructor(
dri,
psi.parameters.map(::getProjection)
) to javaClassKind
Expand Down Expand Up @@ -370,11 +372,19 @@ class DefaultPsiToDocumentableTranslator(
dri = DRI.from(resolved),
name = resolved.name.orEmpty()
)
else ->
TypeConstructor(DRI.from(resolved), type.parameters.map { getProjection(it) })
Regex("kotlin\\.jvm\\.functions\\.Function.*").matches(resolved.qualifiedName ?: "") ||
Regex("java\\.util\\.function\\.Function.*").matches(
resolved.qualifiedName ?: ""
) -> FunctionalTypeConstructor(
DRI.from(resolved),
type.parameters.map { getProjection(it) }
)
else -> GenericTypeConstructor(
DRI.from(resolved),
type.parameters.map { getProjection(it) })
}
}
is PsiArrayType -> TypeConstructor(
is PsiArrayType -> GenericTypeConstructor(
DRI("kotlin", "Array"),
listOf(getProjection(type.componentType))
)
Expand Down Expand Up @@ -411,6 +421,7 @@ class DefaultPsiToDocumentableTranslator(
DTypeParameter(
dri.copy(target = dri.target.nextTarget()),
type.name.orEmpty(),
null,
javadocParser.parseDocumentation(type).toSourceSetDependent(),
null,
mapBounds(type.bounds),
Expand Down
Loading

0 comments on commit 64ec7ad

Please sign in to comment.