From 1e51b98c865f9cbac3637bb22b6b169c553ac5d4 Mon Sep 17 00:00:00 2001 From: IgnatBeresnev Date: Fri, 29 Jul 2022 02:02:26 +0200 Subject: [PATCH 1/2] Fix parsing of static imports in annotation params Fixes #2580 --- .../psi/DefaultPsiToDocumentableTranslator.kt | 19 +++++- .../translators/psi/PsiPackageHelper.kt | 15 +++++ .../DefaultPsiToDocumentableTranslatorTest.kt | 64 +++++++++++++++++++ 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 3c1a2cc794..0ed82566dd 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -682,9 +682,22 @@ class DefaultPsiToDocumentableTranslator( * This is a workaround for static imports from JDK like RetentionPolicy * For some reason they are not represented in the same way than using normal import */ - private fun JvmAnnotationAttributeValue.toValue(): AnnotationParameterValue? = when (this) { - is JvmAnnotationEnumFieldValue -> (field as? PsiElement)?.let { EnumValue(fieldName ?: "", DRI.from(it)) } - else -> null + private fun JvmAnnotationAttributeValue.toValue(): AnnotationParameterValue? { + return when { + this is JvmAnnotationEnumFieldValue -> (field as? PsiElement)?.let { EnumValue(fieldName ?: "", DRI.from(it)) } + // static import of a constant is resolved to constant value instead of a field/link + this.isPsiAnnotationConstantValue() -> this.getPsiAnnotationConstantValue()?.toAnnotationLiteralValue() + else -> null + } + } + + private fun Any.toAnnotationLiteralValue() = when (this) { + is Int -> IntValue(this) + is Long -> LongValue(this) + is Boolean -> BooleanValue(this) + is Float -> FloatValue(this) + is Double -> DoubleValue(this) + else -> StringValue(this.toString()) } private fun PsiAnnotationMemberValue.toValue(): AnnotationParameterValue? = when (this) { diff --git a/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt b/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt new file mode 100644 index 0000000000..cf83c05136 --- /dev/null +++ b/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt @@ -0,0 +1,15 @@ +/** + * Pretend to be from `com.intellij.psi` in order to access package-private declarations + */ +@file:Suppress("PackageDirectoryMismatch") +package com.intellij.psi + +import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue + +/* + * For some reason `PsiAnnotationConstantValue` is package private, + * even though it's returned in public API calls. + */ +internal fun JvmAnnotationAttributeValue.isPsiAnnotationConstantValue() = this is PsiAnnotationConstantValue +internal fun JvmAnnotationAttributeValue.getPsiAnnotationConstantValue(): Any? = + (this as PsiAnnotationConstantValue).constantValue diff --git a/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt b/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt index 1ac54ae209..3f34f02021 100644 --- a/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt +++ b/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt @@ -198,6 +198,70 @@ class DefaultPsiToDocumentableTranslatorTest : BaseAbstractTest() { } } + @Test + fun `should resolve static imports used as annotation param values as literal values`() { + testInline( + """ + |/src/main/java/test/JavaClassUsingAnnotation.java + |package test; + | + |import static test.JavaConstants.STRING; + |import static test.JavaConstants.INTEGER; + |import static test.JavaConstants.LONG; + |import static test.JavaConstants.BOOLEAN; + |import static test.JavaConstants.DOUBLE; + |import static test.JavaConstants.FLOAT; + | + |@JavaAnnotation( + | stringValue = STRING, intValue = INTEGER, longValue = LONG, + | booleanValue = BOOLEAN, doubleValue = DOUBLE, floatValue = FLOAT + |) + |public class JavaClassUsingAnnotation { + |} + | + |/src/main/java/test/JavaAnnotation.java + |package test; + |@Documented + |public @interface JavaAnnotation { + | String stringValue(); + | int intValue(); + | long longValue(); + | boolean booleanValue(); + | double doubleValue(); + | float floatValue(); + |} + | + |/src/main/java/test/JavaConstants.java + |package test; + |public class JavaConstants { + | public static final String STRING = "STRING_CONSTANT_VALUE"; + | public static final int INTEGER = 5; + | public static final long LONG = 6L; + | public static final boolean BOOLEAN = true; + | public static final double DOUBLE = 7.0d; + | public static final float FLOAT = 8.0f; + |} + """.trimIndent(), + configuration + ) { + documentablesMergingStage = { module -> + val testedClass = module.packages.single().classlikes.single { it.name == "JavaClassUsingAnnotation" } + + val annotation = (testedClass as DClass).extra[Annotations]?.directAnnotations?.values?.single()?.single() + checkNotNull(annotation) + + assertEquals("JavaAnnotation", annotation.dri.classNames) + assertEquals(StringValue("STRING_CONSTANT_VALUE"), annotation.params["stringValue"]) + + assertEquals(IntValue(5), annotation.params["intValue"]) + assertEquals(LongValue(6), annotation.params["longValue"]) + assertEquals(BooleanValue(true), annotation.params["booleanValue"]) + assertEquals(DoubleValue(7.0), annotation.params["doubleValue"]) + assertEquals(FloatValue(8.0f), annotation.params["floatValue"]) + } + } + } + class OnlyPsiPlugin : DokkaPlugin() { private val dokkaBase by lazy { plugin() } From 393b5491a4d18f0700a61d1d2338876018254bb2 Mon Sep 17 00:00:00 2001 From: IgnatBeresnev Date: Wed, 3 Aug 2022 15:10:55 +0200 Subject: [PATCH 2/2] Get rid of horrible package-private hack --- .../psi/DefaultPsiToDocumentableTranslator.kt | 7 ++++--- .../kotlin/translators/psi/PsiPackageHelper.kt | 15 --------------- 2 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 0ed82566dd..03e0b9ef50 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -3,6 +3,7 @@ package org.jetbrains.dokka.base.translators.psi import com.intellij.lang.jvm.JvmModifier import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue +import com.intellij.lang.jvm.annotation.JvmAnnotationConstantValue import com.intellij.lang.jvm.annotation.JvmAnnotationEnumFieldValue import com.intellij.lang.jvm.types.JvmReferenceType import com.intellij.openapi.vfs.VirtualFileManager @@ -683,10 +684,10 @@ class DefaultPsiToDocumentableTranslator( * For some reason they are not represented in the same way than using normal import */ private fun JvmAnnotationAttributeValue.toValue(): AnnotationParameterValue? { - return when { - this is JvmAnnotationEnumFieldValue -> (field as? PsiElement)?.let { EnumValue(fieldName ?: "", DRI.from(it)) } + return when (this) { + is JvmAnnotationEnumFieldValue -> (field as? PsiElement)?.let { EnumValue(fieldName ?: "", DRI.from(it)) } // static import of a constant is resolved to constant value instead of a field/link - this.isPsiAnnotationConstantValue() -> this.getPsiAnnotationConstantValue()?.toAnnotationLiteralValue() + is JvmAnnotationConstantValue -> this.constantValue?.toAnnotationLiteralValue() else -> null } } diff --git a/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt b/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt deleted file mode 100644 index cf83c05136..0000000000 --- a/plugins/base/src/main/kotlin/translators/psi/PsiPackageHelper.kt +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Pretend to be from `com.intellij.psi` in order to access package-private declarations - */ -@file:Suppress("PackageDirectoryMismatch") -package com.intellij.psi - -import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue - -/* - * For some reason `PsiAnnotationConstantValue` is package private, - * even though it's returned in public API calls. - */ -internal fun JvmAnnotationAttributeValue.isPsiAnnotationConstantValue() = this is PsiAnnotationConstantValue -internal fun JvmAnnotationAttributeValue.getPsiAnnotationConstantValue(): Any? = - (this as PsiAnnotationConstantValue).constantValue