aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/translators
diff options
context:
space:
mode:
authorMarcin Aman <marcin.aman@gmail.com>2021-02-05 14:55:45 +0100
committerGitHub <noreply@github.com>2021-02-05 14:55:45 +0100
commit70000c87a37caa2a6b518a555f53c98514434403 (patch)
tree3a0e7a2b797b6edfffc0396bb5f9d35708120e9d /plugins/base/src/main/kotlin/translators
parentb44e41ec8e3e26c73affaaa98bbd170fde352d96 (diff)
downloaddokka-70000c87a37caa2a6b518a555f53c98514434403.tar.gz
dokka-70000c87a37caa2a6b518a555f53c98514434403.tar.bz2
dokka-70000c87a37caa2a6b518a555f53c98514434403.zip
Annotations for parameters (#1710)
* Annotations for parameters * Annotations for parameters
Diffstat (limited to 'plugins/base/src/main/kotlin/translators')
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt83
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt70
2 files changed, 98 insertions, 55 deletions
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
index 18231601..51389f37 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -14,6 +14,7 @@ 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.*
@@ -114,7 +115,7 @@ private class DokkaDescriptorVisitor(
}
}
- private fun <T> T.toSourceSetDependent() = if(this != null) mapOf(sourceSet to this) else emptyMap()
+ private fun <T> T.toSourceSetDependent() = if (this != null) mapOf(sourceSet to this) else emptyMap()
suspend fun visitPackageFragmentDescriptor(
descriptor: PackageFragmentDescriptor,
@@ -489,7 +490,8 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(
InheritedMember(inheritedFrom.toSourceSetDependent()),
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
- (descriptor.getAnnotations() + descriptor.fileLevelAnnotations()).toSourceSetDependent().toAnnotations(),
+ (descriptor.getAnnotations() + descriptor.fileLevelAnnotations()).toSourceSetDependent()
+ .toAnnotations(),
)
)
}
@@ -784,36 +786,45 @@ private class DokkaDescriptorVisitor(
)
private suspend fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? =
- map { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name")
+ mapNotNull { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name")
.safeAs<StringValue>()?.value?.let { unquotedValue(it) }
- private suspend fun KotlinType.toBound(): Bound = when (this) {
-
- is DynamicType -> Dynamic
- is AbbreviatedType -> TypeAliased(
- abbreviation.toBound(),
- expandedType.toBound()
- )
- else -> when (val ctor = constructor.declarationDescriptor) {
- is TypeParameterDescriptor -> TypeParameter(
- dri = DRI.from(ctor),
- 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()
+ private suspend fun KotlinType.toBound(): Bound {
+ suspend fun <T : AnnotationTarget> annotations(): PropertyContainer<T> =
+ getAnnotations().takeIf { it.isNotEmpty() }?.let { annotations ->
+ PropertyContainer.withAll(annotations.toSourceSetDependent().toAnnotations())
+ } ?: PropertyContainer.empty()
+
+ return when (this) {
+ is DynamicType -> Dynamic
+ is AbbreviatedType -> TypeAliased(
+ abbreviation.toBound(),
+ expandedType.toBound()
)
- else -> GenericTypeConstructor(
- DRI.from(ctor!!), // TODO: remove '!!'
- arguments.map { it.toProjection() },
- annotations.getPresentableName()
- )
- }.let {
- if (isMarkedNullable) Nullable(it) else it
+ else -> when (val ctor = constructor.declarationDescriptor) {
+ is TypeParameterDescriptor -> TypeParameter(
+ dri = DRI.from(ctor),
+ name = ctor.name.asString(),
+ presentableName = annotations.getPresentableName(),
+ extra = annotations()
+ )
+ is FunctionClassDescriptor -> FunctionalTypeConstructor(
+ DRI.from(ctor),
+ arguments.map { it.toProjection() },
+ isExtensionFunction = isExtensionFunctionType || isBuiltinExtensionFunctionalType,
+ isSuspendable = isSuspendFunctionTypeOrSubtype,
+ presentableName = annotations.getPresentableName(),
+ extra = annotations()
+ )
+ else -> GenericTypeConstructor(
+ DRI.from(ctor!!), // TODO: remove '!!'
+ arguments.map { it.toProjection() },
+ annotations.getPresentableName(),
+ extra = annotations()
+ )
+ }.let {
+ if (isMarkedNullable) Nullable(it) else it
+ }
}
}
@@ -823,7 +834,7 @@ private class DokkaDescriptorVisitor(
private suspend fun TypeProjection.formPossiblyVariant(): Projection =
type.toBound().wrapWithVariance(projectionKind)
- private suspend fun TypeParameterDescriptor.variantTypeParameter(type: TypeParameter) =
+ private fun TypeParameterDescriptor.variantTypeParameter(type: TypeParameter) =
type.wrapWithVariance(variance)
private fun <T : Bound> T.wrapWithVariance(variance: org.jetbrains.kotlin.types.Variance) =
@@ -909,7 +920,7 @@ private class DokkaDescriptorVisitor(
private suspend fun Annotated.getAnnotations() = annotations.parallelMapNotNull { it.toAnnotation() }
- private suspend fun ConstantValue<*>.toValue(): AnnotationParameterValue? = when (this) {
+ private fun ConstantValue<*>.toValue(): AnnotationParameterValue? = when (this) {
is ConstantsAnnotationValue -> value.toAnnotation()?.let { AnnotationValue(it) }
is ConstantsArrayValue -> ArrayValue(value.mapNotNull { it.toValue() })
is ConstantsEnumValue -> EnumValue(
@@ -933,7 +944,7 @@ private class DokkaDescriptorVisitor(
else -> StringValue(unquotedValue(toString()))
}
- private suspend fun AnnotationDescriptor.toAnnotation(scope: Annotations.AnnotationScope = Annotations.AnnotationScope.DIRECT): Annotations.Annotation =
+ private fun AnnotationDescriptor.toAnnotation(scope: Annotations.AnnotationScope = Annotations.AnnotationScope.DIRECT): Annotations.Annotation =
Annotations.Annotation(
DRI.from(annotationClass as DeclarationDescriptor),
allValueArguments.map { it.key.asString() to it.value.toValue() }.filter {
@@ -944,7 +955,8 @@ private class DokkaDescriptorVisitor(
)
private fun AnnotationDescriptor.mustBeDocumented(): Boolean =
- annotationClass?.annotations?.hasAnnotation(FqName("kotlin.annotation.MustBeDocumented")) ?: false
+ if (source.toString() == "NO_SOURCE") false
+ else annotationClass?.annotations?.hasAnnotation(FqName("kotlin.annotation.MustBeDocumented")) ?: false
private suspend fun PropertyDescriptor.getAnnotationsWithBackingField(): List<Annotations.Annotation> =
getAnnotations() + (backingField?.getAnnotations() ?: emptyList())
@@ -1010,13 +1022,14 @@ private class DokkaDescriptorVisitor(
private fun ConstantsEnumValue.fullEnumEntryName() =
"${this.enumClassId.relativeClassName.asString()}.${this.enumEntryName.identifier}"
- private fun DeclarationDescriptorWithSource.ktFile(): KtFile? = (source.containingFile as? PsiSourceFile)?.psiFile as? KtFile
+ private fun DeclarationDescriptorWithSource.ktFile(): KtFile? =
+ (source.containingFile as? PsiSourceFile)?.psiFile as? KtFile
private suspend fun DeclarationDescriptorWithSource.fileLevelAnnotations() = ktFile()
?.let { file -> resolutionFacade.resolveSession.getFileAnnotations(file) }
?.toList()
+ ?.parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) }
.orEmpty()
- .parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) }
}
private data class AncestryLevel(
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
index 5b913dcb..c09d1156 100644
--- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
@@ -22,9 +22,11 @@ import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.nextTarget
import org.jetbrains.dokka.links.withClass
import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.AnnotationTarget
import org.jetbrains.dokka.model.doc.DocumentationNode
import org.jetbrains.dokka.model.doc.Param
import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.querySingle
@@ -200,8 +202,15 @@ class DefaultPsiToDocumentableTranslator(
parseSupertypes(superTypes)
val (regularFunctions, accessors) = splitFunctionsAndAccessors()
val documentation = javadocParser.parseDocumentation(this).toSourceSetDependent()
- val allFunctions = async { regularFunctions.parallelMapNotNull { if (!it.isConstructor) parseFunction(it, parentDRI = dri) else null } +
- superMethods.parallelMap { parseFunction(it.first, inheritedFrom = it.second) } }
+ val allFunctions = async {
+ regularFunctions.parallelMapNotNull {
+ if (!it.isConstructor) parseFunction(
+ it,
+ parentDRI = dri
+ ) else null
+ } +
+ superMethods.parallelMap { parseFunction(it.first, inheritedFrom = it.second) }
+ }
val source = PsiDocumentableSource(this).toSourceSetDependent()
val classlikes = async { innerClasses.asIterable().parallelMap { parseClasslike(it, dri) } }
val visibility = getVisibility().toSourceSetDependent()
@@ -406,40 +415,61 @@ class DefaultPsiToDocumentableTranslator(
Annotations.Annotation(DRI("kotlin.jvm", "JvmStatic"), emptyMap())
}
- private fun getBound(type: PsiType): Bound =
- cachedBounds.getOrPut(type.canonicalText) {
- when (type) {
- is PsiClassReferenceType -> {
- val resolved: PsiClass = type.resolve()
- ?: return UnresolvedBound(type.presentableText)
+ private fun getBound(type: PsiType): Bound {
+ fun annotationsFromType(): List<Annotations.Annotation> = type.annotations.toList().toListOfAnnotations()
+
+ fun <T : AnnotationTarget> annotations(): PropertyContainer<T> =
+ annotationsFromType().takeIf { it.isNotEmpty() }?.let { annotations ->
+ PropertyContainer.withAll(annotations.toSourceSetDependent().toAnnotations())
+ } ?: PropertyContainer.empty()
+
+ fun bound() = when (type) {
+ is PsiClassReferenceType ->
+ type.resolve()?.let { resolved ->
when {
- resolved.qualifiedName == "java.lang.Object" -> JavaObject
+ resolved.qualifiedName == "java.lang.Object" -> JavaObject(annotations())
resolved is PsiTypeParameter ->
TypeParameter(
dri = DRI.from(resolved),
- name = resolved.name.orEmpty()
+ name = resolved.name.orEmpty(),
+ extra = annotations()
)
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) }
+ type.parameters.map { getProjection(it) },
+ extra = annotations()
)
else -> GenericTypeConstructor(
DRI.from(resolved),
- type.parameters.map { getProjection(it) })
+ type.parameters.map { getProjection(it) },
+ extra = annotations()
+ )
}
- }
- is PsiArrayType -> GenericTypeConstructor(
- DRI("kotlin", "Array"),
- listOf(getProjection(type.componentType))
- )
- is PsiPrimitiveType -> if (type.name == "void") Void else PrimitiveJavaType(type.name)
- is PsiImmediateClassType -> JavaObject
- else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser")
+ } ?: UnresolvedBound(type.presentableText)
+ is PsiArrayType -> GenericTypeConstructor(
+ DRI("kotlin", "Array"),
+ listOf(getProjection(type.componentType)),
+ extra = annotations()
+ )
+ is PsiPrimitiveType -> if (type.name == "void") Void else PrimitiveJavaType(type.name)
+ is PsiImmediateClassType -> JavaObject(annotations())
+ else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser")
+ }
+
+ //We would like to cache most of the bounds since it is not common to annotate them,
+ //but if this is the case, we treat them as 'one of'
+ return if (annotationsFromType().isEmpty()) {
+ cachedBounds.getOrPut(type.canonicalText) {
+ bound()
}
+ } else {
+ bound()
}
+ }
+
private fun getVariance(type: PsiWildcardType): Projection = when {
type.extendsBound != PsiType.NULL -> Covariance(getBound(type.extendsBound))