From 13746f4afacd72576515dd94ba1167546418421f Mon Sep 17 00:00:00 2001 From: owengray-google Date: Fri, 8 Apr 2022 11:53:52 -0400 Subject: Rework AnnotationTarget to be stricter (#2414) --- .../DefaultDescriptorToDocumentableTranslator.kt | 19 +++--- .../psi/DefaultPsiToDocumentableTranslator.kt | 5 +- ...efaultDescriptorToDocumentableTranslatorTest.kt | 67 +++++++++++++++++++++- .../src/test/kotlin/KotlinAsJavaPluginTest.kt | 52 +++++++++++++++++ 4 files changed, 131 insertions(+), 12 deletions(-) (limited to 'plugins') diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 259f374a..6bc8774d 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -13,8 +13,9 @@ import org.jetbrains.dokka.analysis.KotlinAnalysis 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.typeConstructorsBeingExceptions import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser +import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator +import org.jetbrains.dokka.base.translators.typeConstructorsBeingExceptions import org.jetbrains.dokka.base.translators.unquotedValue import org.jetbrains.dokka.links.* import org.jetbrains.dokka.links.Callable @@ -31,7 +32,6 @@ import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.utilities.parallelMap import org.jetbrains.dokka.utilities.parallelMapNotNull import org.jetbrains.kotlin.KtNodeTypes -import org.jetbrains.dokka.model.BooleanConstant import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType import org.jetbrains.kotlin.builtins.isExtensionFunctionType @@ -68,16 +68,16 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.nio.file.Paths import org.jetbrains.kotlin.resolve.constants.AnnotationValue as ConstantsAnnotationValue import org.jetbrains.kotlin.resolve.constants.ArrayValue as ConstantsArrayValue -import org.jetbrains.kotlin.resolve.constants.EnumValue as ConstantsEnumValue -import org.jetbrains.kotlin.resolve.constants.KClassValue as ConstantsKtClassValue +import org.jetbrains.kotlin.resolve.constants.BooleanValue as ConstantsBooleanValue import org.jetbrains.kotlin.resolve.constants.DoubleValue as ConstantsDoubleValue +import org.jetbrains.kotlin.resolve.constants.EnumValue as ConstantsEnumValue import org.jetbrains.kotlin.resolve.constants.FloatValue as ConstantsFloatValue import org.jetbrains.kotlin.resolve.constants.IntValue as ConstantsIntValue +import org.jetbrains.kotlin.resolve.constants.KClassValue as ConstantsKtClassValue import org.jetbrains.kotlin.resolve.constants.LongValue as ConstantsLongValue +import org.jetbrains.kotlin.resolve.constants.NullValue as ConstantsNullValue import org.jetbrains.kotlin.resolve.constants.UIntValue as ConstantsUIntValue import org.jetbrains.kotlin.resolve.constants.ULongValue as ConstantsULongValue -import org.jetbrains.kotlin.resolve.constants.BooleanValue as ConstantsBooleanValue -import org.jetbrains.kotlin.resolve.constants.NullValue as ConstantsNullValue class DefaultDescriptorToDocumentableTranslator( private val context: DokkaContext @@ -773,7 +773,9 @@ private class DokkaDescriptorVisitor( private suspend fun toTypeConstructor(kt: KotlinType) = GenericTypeConstructor( DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), - kt.arguments.map { it.toProjection() }) + kt.arguments.map { it.toProjection() }, + extra = PropertyContainer.withAll(kt.getAnnotations().toSourceSetDependent().toAnnotations()) + ) private suspend fun buildAncestryInformation( kotlinType: KotlinType @@ -834,7 +836,8 @@ private class DokkaDescriptorVisitor( is DynamicType -> Dynamic is AbbreviatedType -> TypeAliased( abbreviation.toBound(), - expandedType.toBound() + expandedType.toBound(), + annotations() ) else -> when (val ctor = constructor.declarationDescriptor) { is TypeParameterDescriptor -> TypeParameter( diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 4b2d7720..f9199154 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -472,13 +472,14 @@ class DefaultPsiToDocumentableTranslator( extra = type.annotations() ) } - } ?: UnresolvedBound(type.presentableText) + } ?: UnresolvedBound(type.presentableText, type.annotations()) is PsiArrayType -> GenericTypeConstructor( DRI("kotlin", "Array"), listOf(getProjection(type.componentType)), extra = type.annotations() ) - is PsiPrimitiveType -> if (type.name == "void") Void else PrimitiveJavaType(type.name) + is PsiPrimitiveType -> if (type.name == "void") Void + else PrimitiveJavaType(type.name, type.annotations()) is PsiImmediateClassType -> JavaObject(type.annotations()) else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser") } diff --git a/plugins/base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt b/plugins/base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt index 798a3f3b..fd9fcc5d 100644 --- a/plugins/base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt +++ b/plugins/base/src/test/kotlin/translators/DefaultDescriptorToDocumentableTranslatorTest.kt @@ -1,13 +1,15 @@ package translators import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* -import org.junit.jupiter.api.Assertions.* import org.jetbrains.dokka.model.doc.CodeBlock import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.Assert +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test class DefaultDescriptorToDocumentableTranslatorTest : BaseAbstractTest() { @@ -663,4 +665,65 @@ class DefaultDescriptorToDocumentableTranslatorTest : BaseAbstractTest() { } } } + + val javaConfiguration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/main/java") + includeNonPublic = true + } + } + } + + @Disabled // The compiler throws away annotations on unresolved types upstream + @Test + fun `Can annotate unresolved type`() { + testInline( + """ + |/src/main/java/sample/FooLibrary.kt + |package sample; + |@MustBeDocumented + |@Target(AnnotationTarget.TYPE) + |annotation class Hello() + |fun bar(): @Hello() TypeThatDoesntResolve + """.trimMargin(), + javaConfiguration + ) { + documentablesMergingStage = { module -> + val type = module.packages.single().functions.single().type as GenericTypeConstructor + assertEquals( + Annotations.Annotation(DRI("sample", "Hello"), emptyMap()), + type.extra[Annotations]?.directAnnotations?.values?.single()?.single() + ) + } + } + } + + /** + * Kotlin Int becomes java int. Java int cannot be annotated in source, but Kotlin Int can be. + * This is paired with KotlinAsJavaPluginTest.`Java primitive annotations work`() + */ + @Test + fun `Java primitive annotations work`() { + testInline( + """ + |/src/main/java/sample/FooLibrary.kt + |package sample; + |@MustBeDocumented + |@Target(AnnotationTarget.TYPE) + |annotation class Hello() + |fun bar(): @Hello() Int + """.trimMargin(), + javaConfiguration + ) { + documentablesMergingStage = { module -> + val type = module.packages.single().functions.single().type as GenericTypeConstructor + assertEquals( + Annotations.Annotation(DRI("sample", "Hello"), emptyMap()), + type.extra[Annotations]?.directAnnotations?.values?.single()?.single() + ) + assertEquals("kotlin/Int///PointingToDeclaration/", type.dri.toString()) + } + } + } } diff --git a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt index b9627f9b..0235b9d1 100644 --- a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt +++ b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt @@ -4,10 +4,14 @@ import matchers.content.* import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.jdk +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.Annotations +import org.jetbrains.dokka.model.GenericTypeConstructor import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.pages.* import org.jetbrains.kotlin.utils.addToStdlib.cast import org.junit.Assert +import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import signatures.Parameter import signatures.Parameters @@ -534,6 +538,54 @@ class KotlinAsJavaPluginTest : BaseAbstractTest() { } } } + + /** + * Kotlin Int becomes java int. Java int cannot be annotated in source, but Kotlin Int can be. + * This is paired with DefaultDescriptorToDocumentableTranslatorTest.`Java primitive annotations work`() + * + * This test currently does not do anything because Kotlin.Int currently becomes java.lang.Integer not primitive int + */ + @Test + fun `Java primitive annotations work`() { + val writerPlugin = TestOutputWriterPlugin() + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + externalDocumentationLinks = listOf( + DokkaConfiguration.ExternalDocumentationLink.jdk(8), + stdlibExternalDocumentationLink + ) + } + } + } + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt + |package kotlinAsJavaPlugin + |@MustBeDocumented + |@Target(AnnotationTarget.TYPE) + |annotation class Hello() + |fun bar(): @Hello() Int + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin), + cleanupOutput = true + ) { + documentablesTransformationStage = { module -> + val type = module.packages.single() + .classlikes.first { it.name == "TestKt" } + .functions.single() + .type as GenericTypeConstructor + Assertions.assertEquals( + Annotations.Annotation(DRI("kotlinAsJavaPlugin", "Hello"), emptyMap()), + type.extra[Annotations]?.directAnnotations?.values?.single()?.single() + ) + // A bug; the GenericTypeConstructor cast should fail and this should be a PrimitiveJavaType + Assertions.assertEquals("java.lang/Integer///PointingToDeclaration/", type.dri.toString()) + } + } + } } private val ContentNode.mainContents: List -- cgit