Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing of JvmName #1675

Merged
merged 3 commits into from
Dec 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions core/src/main/kotlin/model/additionalExtras.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,48 @@ class AdditionalModifiers(val content: SourceSetDependent<Set<ExtraModifiers>>)

fun SourceSetDependent<Set<ExtraModifiers>>.toAdditionalModifiers() = AdditionalModifiers(this)

class Annotations(val content: SourceSetDependent<List<Annotation>>) : ExtraProperty<Documentable> {
data class Annotations(
private val myContent: SourceSetDependent<List<Annotation>>
) : ExtraProperty<Documentable> {
companion object : ExtraProperty.Key<Documentable, Annotations> {
override fun mergeStrategyFor(left: Annotations, right: Annotations): MergeStrategy<Documentable> =
MergeStrategy.Replace(Annotations(left.content + right.content))
MergeStrategy.Replace(Annotations(left.myContent + right.myContent))
}

override val key: ExtraProperty.Key<Documentable, *> = Annotations

data class Annotation(val dri: DRI, val params: Map<String, AnnotationParameterValue>, val mustBeDocumented: Boolean = false) {
data class Annotation(
val dri: DRI,
val params: Map<String, AnnotationParameterValue>,
val mustBeDocumented: Boolean = false,
val scope: AnnotationScope = AnnotationScope.DIRECT
) {
override fun equals(other: Any?): Boolean = when (other) {
is Annotation -> dri == other.dri
else -> false
}

override fun hashCode(): Int = dri.hashCode()
}

@Deprecated("Use directAnnotations or fileLevelAnnotations")
val content: SourceSetDependent<List<Annotation>>
get() = myContent

val directAnnotations: SourceSetDependent<List<Annotation>> = annotationsByScope(AnnotationScope.DIRECT)

val fileLevelAnnotations: SourceSetDependent<List<Annotation>> = annotationsByScope(AnnotationScope.FILE)

private fun annotationsByScope(scope: AnnotationScope): SourceSetDependent<List<Annotation>> =
myContent.entries.mapNotNull { (key, value) ->
val withoutFileLevel = value.filter { it.scope == scope }
if (withoutFileLevel.isEmpty()) null
else Pair(key, withoutFileLevel)
}.toMap()

enum class AnnotationScope {
DIRECT, FILE
}
}

fun SourceSetDependent<List<Annotations.Annotation>>.toAnnotations() = Annotations(this)
Expand Down Expand Up @@ -65,7 +91,7 @@ data class ActualTypealias(val underlyingType: SourceSetDependent<Bound>) : Extr
override val key: ExtraProperty.Key<DClasslike, ActualTypealias> = ActualTypealias
}

data class ConstructorValues(val values: SourceSetDependent<List<String>>) : ExtraProperty<DEnumEntry>{
data class ConstructorValues(val values: SourceSetDependent<List<String>>) : ExtraProperty<DEnumEntry> {
companion object : ExtraProperty.Key<DEnumEntry, ConstructorValues> {
override fun mergeStrategyFor(left: ConstructorValues, right: ConstructorValues) =
MergeStrategy.Replace(ConstructorValues(left.values + right.values))
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/kotlin/model/jvmName.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.jetbrains.dokka.model

import org.jetbrains.dokka.links.DRI

fun DRI.isJvmName(): Boolean = packageName == "kotlin.jvm" && classNames == "JvmName"

fun Annotations.Annotation.isJvmName(): Boolean = dri.isJvmName()
4 changes: 2 additions & 2 deletions plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface JvmSignatureUtils {
joinToString("") { it.name.toLowerCase() + " " }

fun <T : Documentable> WithExtraProperties<T>.annotations(): SourceSetDependent<List<Annotations.Annotation>> =
extra[Annotations]?.content ?: emptyMap()
extra[Annotations]?.directAnnotations ?: emptyMap()

private fun PageContentBuilder.DocumentableContentBuilder.annotations(
d: Documentable,
Expand Down Expand Up @@ -131,7 +131,7 @@ interface JvmSignatureUtils {
}

fun <T : Documentable> WithExtraProperties<T>.stylesIfDeprecated(sourceSetData: DokkaSourceSet): Set<TextStyle> =
if (extra[Annotations]?.content?.get(sourceSetData)?.any {
if (extra[Annotations]?.directAnnotations?.get(sourceSetData)?.any {
it.dri == DRI("kotlin", "Deprecated")
|| it.dri == DRI("java.lang", "Deprecated")
} == true) setOf(TextStyle.Strikethrough) else emptySet()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fun <T> T.isDeprecated() where T : WithExtraProperties<out Documentable> =

val <T> T.deprecatedAnnotation where T : WithExtraProperties<out Documentable>
get() = extra[Annotations]?.let { annotations ->
annotations.content.values.flatten().firstOrNull {
annotations.directAnnotations.values.flatten().firstOrNull {
it.dri.toString() == "kotlin/Deprecated///PointingToDeclaration/" ||
it.dri.toString() == "java.lang/Deprecated///PointingToDeclaration/"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class SinceKotlinTransformer(val context: DokkaContext) : DocumentableTransforme

private fun Documentable.appendSinceKotlin() =
sourceSets.fold(documentation) { acc, sourceSet ->
safeAs<WithExtraProperties<Documentable>>()?.extra?.get(Annotations)?.content?.get(sourceSet)?.find {
safeAs<WithExtraProperties<Documentable>>()?.extra?.get(Annotations)?.directAnnotations?.get(sourceSet)?.find {
it.dri == DRI("kotlin", "SinceKotlin")
}?.params?.get("version").safeAs<StringValue>()?.value?.let { version ->
acc.mapValues {
Expand Down
3 changes: 3 additions & 0 deletions plugins/base/src/main/kotlin/translators/annotationsValue.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.jetbrains.dokka.base.translators

internal fun unquotedValue(value: String): String = value.removeSurrounding("\"")
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jetbrains.dokka.analysis.from
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.parsers.MarkdownParser
import org.jetbrains.dokka.base.translators.isDirectlyAnException
import org.jetbrains.dokka.base.translators.unquotedValue
import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.links.Callable
import org.jetbrains.dokka.model.*
Expand All @@ -19,10 +20,8 @@ import org.jetbrains.dokka.model.doc.*
import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.query
import org.jetbrains.dokka.plugability.querySingle
import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTranslator
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
Expand All @@ -33,7 +32,6 @@ import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
import org.jetbrains.kotlin.codegen.isJvmStaticInObjectOrClassOrInterface
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.kdoc.findKDoc
Expand All @@ -51,8 +49,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
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.resolve.source.PsiSourceFile
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.typeConstructor
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
Expand Down Expand Up @@ -117,7 +115,7 @@ private class DokkaDescriptorVisitor(
}
}

private fun <T> T.toSourceSetDependent() = mapOf(sourceSet to this)
private fun <T> T.toSourceSetDependent() = if(this != null) mapOf(sourceSet to this) else emptyMap()

suspend fun visitPackageFragmentDescriptor(
descriptor: PackageFragmentDescriptor,
Expand Down Expand Up @@ -436,13 +434,16 @@ private class DokkaDescriptorVisitor(
sourceSets = setOf(sourceSet),
generics = generics.await(),
isExpectActual = (isExpect || isActual),
extra = PropertyContainer.withAll(listOfNotNull(
(descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField()
.toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotationsWithBackingField().toSourceSetDependent().toAnnotations(),
descriptor.getDefaultValue()?.let { DefaultValue(it) },
InheritedMember(inheritedFrom.toSourceSetDependent()),
))
extra = PropertyContainer.withAll(
listOfNotNull(
(descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField()
.toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(),
(descriptor.getAnnotationsWithBackingField() + descriptor.fileLevelAnnotations()).toSourceSetDependent()
.toAnnotations(),
descriptor.getDefaultValue()?.let { DefaultValue(it) },
InheritedMember(inheritedFrom.toSourceSetDependent()),
)
)
)
}
}
Expand Down Expand Up @@ -489,7 +490,7 @@ private class DokkaDescriptorVisitor(
extra = PropertyContainer.withAll(
InheritedMember(inheritedFrom.toSourceSetDependent()),
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations()
(descriptor.getAnnotations() + descriptor.fileLevelAnnotations()).toSourceSetDependent().toAnnotations(),
)
)
}
Expand Down Expand Up @@ -588,7 +589,7 @@ private class DokkaDescriptorVisitor(
val name = run {
val modifier = if (isGetter) "get" else "set"
val rawName = propertyDescriptor.name.asString()
"$modifier${rawName[0].toUpperCase()}${rawName.drop(1)}"
"$modifier${rawName.capitalize()}"
}

val parameters =
Expand Down Expand Up @@ -782,8 +783,7 @@ 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")
.safeAs<StringValue>()?.value?.drop(1)
?.dropLast(1) // Dropping enclosing doublequotes because we don't want to have it in our custom signature serializer
.safeAs<StringValue>()?.value?.let { unquotedValue(it) }

private suspend fun KotlinType.toBound(): Bound = when (this) {

Expand Down Expand Up @@ -928,19 +928,25 @@ private class DokkaDescriptorVisitor(
)
}
}
else -> StringValue(toString())
else -> StringValue(unquotedValue(toString()))
}

private suspend fun AnnotationDescriptor.toAnnotation(): Annotations.Annotation {
private suspend fun AnnotationDescriptor.toAnnotation(scope: Annotations.AnnotationScope = Annotations.AnnotationScope.DIRECT): Annotations.Annotation {
val dri = DRI.from(annotationClass as DeclarationDescriptor)
return Annotations.Annotation(
DRI.from(annotationClass as DeclarationDescriptor),
allValueArguments.map { it.key.asString() to it.value.toValue() }.filter {
it.second != null
}.toMap() as Map<String, AnnotationParameterValue>,
annotationClass!!.annotations.hasAnnotation(FqName("kotlin.annotation.MustBeDocumented"))
mustBeDocumented(dri),
scope
)
}

private fun AnnotationDescriptor.mustBeDocumented(dri: DRI): Boolean =
if (dri.isJvmName()) false
else annotationClass!!.annotations.hasAnnotation(FqName("kotlin.annotation.MustBeDocumented"))

private suspend fun PropertyDescriptor.getAnnotationsWithBackingField(): List<Annotations.Annotation> =
getAnnotations() + (backingField?.getAnnotations() ?: emptyList())

Expand Down Expand Up @@ -1004,6 +1010,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 suspend fun DeclarationDescriptorWithSource.fileLevelAnnotations() = ktFile()
?.let { file -> resolutionFacade.resolveSession.getFileAnnotations(file) }
?.toList()
.orEmpty()
.parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) }
}

private data class AncestryLevel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.translators.isDirectlyAnException
import org.jetbrains.dokka.base.translators.psi.parsers.JavaDocumentationParser
import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser
import org.jetbrains.dokka.base.translators.unquotedValue
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.nextTarget
import org.jetbrains.dokka.links.withClass
Expand Down Expand Up @@ -530,6 +531,9 @@ class DefaultPsiToDocumentableTranslator(
private fun JvmAnnotationAttribute.toValue(): AnnotationParameterValue = when (this) {
is PsiNameValuePair -> value?.toValue() ?: StringValue("")
else -> StringValue(this.attributeName)
}.let { annotationValue ->
if (annotationValue is StringValue) annotationValue.copy(unquotedValue(annotationValue.value))
else annotationValue
}

private fun PsiAnnotationMemberValue.toValue(): AnnotationParameterValue? = when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import matchers.content.*
import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.pages.PackagePageNode
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.Annotations
import org.jetbrains.dokka.model.StringValue
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.junit.jupiter.api.Test
import utils.ParamAttributes
import utils.bareSignature
import utils.propertySignature
import kotlin.test.assertEquals
import kotlin.test.assertFalse


class ContentForAnnotationsTest : BaseAbstractTest() {
Expand All @@ -18,6 +24,7 @@ class ContentForAnnotationsTest : BaseAbstractTest() {
sourceSet {
sourceRoots = listOf("src/")
analysisPlatform = "jvm"
classpath += jvmStdlibPath!!
}
}
}
Expand Down Expand Up @@ -218,4 +225,43 @@ class ContentForAnnotationsTest : BaseAbstractTest() {
}
}
}

@Test
fun `JvmName for property with setter and getter`(){
testInline(
"""
|/src/main/kotlin/test/source.kt
|package test
|@get:JvmName("xd")
|@set:JvmName("asd")
|var property: String
| get() = ""
| set(value) {}
""".trimIndent(), testConfiguration) {
documentablesCreationStage = { modules ->
fun expectedAnnotation(name: String) = Annotations.Annotation(
dri = DRI("kotlin.jvm", "JvmName"),
params = mapOf("name" to StringValue(name)),
scope = Annotations.AnnotationScope.DIRECT,
mustBeDocumented = false
)

val property = modules.flatMap { it.packages }.flatMap { it.properties }.first()
val getterAnnotation = property.getter?.extra?.get(Annotations)?.let {
it.directAnnotations.entries.firstNotNullResult { (_, annotations) -> annotations.firstOrNull() }
}
val setterAnnotation = property.getter?.extra?.get(Annotations)?.let {
it.directAnnotations.entries.firstNotNullResult { (_, annotations) -> annotations.firstOrNull() }
}

assertEquals(expectedAnnotation("xd"), getterAnnotation)
assertFalse(getterAnnotation?.mustBeDocumented!!)
assertEquals(Annotations.AnnotationScope.DIRECT, getterAnnotation.scope)

assertEquals(expectedAnnotation("asd"), setterAnnotation)
assertFalse(setterAnnotation?.mustBeDocumented!!)
assertEquals(Annotations.AnnotationScope.DIRECT, setterAnnotation.scope)
}
}
}
}
Loading