diff options
author | Marcin Aman <marcin.aman@gmail.com> | 2021-02-05 14:55:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-05 14:55:45 +0100 |
commit | 70000c87a37caa2a6b518a555f53c98514434403 (patch) | |
tree | 3a0e7a2b797b6edfffc0396bb5f9d35708120e9d /plugins/base/src/main/kotlin/translators | |
parent | b44e41ec8e3e26c73affaaa98bbd170fde352d96 (diff) | |
download | dokka-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')
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)) |