From 7cfdd8a512adb6b8589328610efb5bd56c3c0dd7 Mon Sep 17 00:00:00 2001
From: Szymon Świstun <sswistun@virtuslab.com>
Date: Wed, 11 Mar 2020 15:07:56 +0100
Subject: Add annotations to extra properties

---
 .../DefaultDescriptorToDocumentableTranslator.kt   | 86 ++++++++++++++--------
 plugins/base/src/test/kotlin/model/ClassesTest.kt  | 18 ++++-
 2 files changed, 70 insertions(+), 34 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 eb23ffd7..e2afefe5 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -5,8 +5,6 @@ import org.jetbrains.dokka.links.Callable
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.links.withClass
 import org.jetbrains.dokka.model.*
-import org.jetbrains.dokka.model.DEnum
-import org.jetbrains.dokka.model.DFunction
 import org.jetbrains.dokka.model.doc.DocumentationNode
 import org.jetbrains.dokka.model.properties.PropertyContainer
 import org.jetbrains.dokka.pages.PlatformData
@@ -21,9 +19,7 @@ import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBo
 import org.jetbrains.kotlin.resolve.DescriptorUtils
 import org.jetbrains.kotlin.resolve.calls.components.isVararg
 import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
-import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
-import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
-import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
+import org.jetbrains.kotlin.resolve.descriptorUtil.*
 import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
 import org.jetbrains.kotlin.resolve.scopes.MemberScope
 import org.jetbrains.kotlin.types.KotlinType
@@ -86,6 +82,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent)
             ClassKind.OBJECT -> objectDescriptor(descriptor, parent)
             ClassKind.INTERFACE -> interfaceDescriptor(descriptor, parent)
+            ClassKind.ANNOTATION_CLASS -> annotationDescriptor(descriptor, parent)
             else -> classDescriptor(descriptor, parent)
         }
 
@@ -107,7 +104,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             generics = descriptor.typeConstructor.parameters.map { it.toTypeParameter() },
             companion = descriptor.companion(driWithPlatform),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -127,7 +124,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             supertypes = PlatformDependent.from(platformData, info.supertypes),
             documentation = info.docs,
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -150,7 +147,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             documentation = info.docs,
             companion = descriptor.companion(driWithPlatform),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -166,7 +163,27 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             functions = scope.functions(driWithPlatform),
             properties = scope.properties(driWithPlatform),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
+        )
+    }
+
+    fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation {
+        val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
+        val scope = descriptor.unsubstitutedMemberScope
+
+        return DAnnotation(
+            dri = driWithPlatform.dri,
+            name = descriptor.name.asString(),
+            documentation = descriptor.resolveDescriptorData(platformData),
+            classlikes = scope.classlikes(driWithPlatform),
+            functions = scope.functions(driWithPlatform),
+            properties = scope.properties(driWithPlatform),
+            platformData = listOf(platformData),
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()),
+            companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) },
+            visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())),
+            constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) },
+            sources = descriptor.createSources()
         )
     }
 
@@ -197,7 +214,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             companion = descriptor.companion(driWithPlatform),
             supertypes = PlatformDependent.from(platformData, info.supertypes),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -213,7 +230,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             },
             sources = actual,
             getter = descriptor.accessors.filterIsInstance<PropertyGetterDescriptor>().singleOrNull()?.let {
-               visitPropertyAccessorDescriptor(it, descriptor, dri)
+                visitPropertyAccessorDescriptor(it, descriptor, dri)
             },
             setter = descriptor.accessors.filterIsInstance<PropertySetterDescriptor>().singleOrNull()?.let {
                 visitPropertyAccessorDescriptor(it, descriptor, dri)
@@ -223,7 +240,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             modifier = descriptor.modifier(),
             type = descriptor.returnType!!.toBound(),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -248,7 +265,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             modifier = descriptor.modifier(),
             type = descriptor.returnType!!.toBound(),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -272,7 +289,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             modifier = descriptor.modifier(),
             generics = descriptor.typeParameters.map { it.toTypeParameter() },
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -302,7 +319,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
                 type = this.type.toBound(),
                 documentation = descriptor.resolveDescriptorData(platformData),
                 platformData = listOf(platformData),
-                extra = descriptor.additionalExtras()
+                extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
             )
 
         val name = run {
@@ -336,7 +353,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             },
             sources = descriptor.createSources(),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations())
         )
     }
 
@@ -347,7 +364,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             type = descriptor.type.toBound(),
             documentation = descriptor.resolveDescriptorData(platformData),
             platformData = listOf(platformData),
-            extra = descriptor.additionalExtras()
+            extra = PropertyContainer.withAll(descriptor.additionalExtras())
         )
 
     private fun MemberScope.functions(parent: DRIWithPlatformInfo): List<DFunction> =
@@ -395,7 +412,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             PlatformDependent.from(platformData, getDocumentation()),
             upperBounds.map { it.toBound() },
             listOf(platformData),
-            extra = additionalExtras()
+            extra = PropertyContainer.withAll(additionalExtras())
         )
 
     private fun KotlinType.toBound(): Bound = when (val ctor = constructor.declarationDescriptor) {
@@ -444,7 +461,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
         PlatformDependent(mapOf(platformData to DescriptorDocumentableSource(this)))
     }
 
-    inline fun <reified D : Documentable> FunctionDescriptor.additionalExtras(): PropertyContainer<D> = listOfNotNull(
+    fun FunctionDescriptor.additionalExtras() = listOfNotNull(
         ExtraModifiers.DYNAMIC.takeIf { isDynamic() },
         ExtraModifiers.INFIX.takeIf { isInfix },
         ExtraModifiers.INLINE.takeIf { isInline },
@@ -454,18 +471,18 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
         ExtraModifiers.TAILREC.takeIf { isTailrec },
         ExtraModifiers.EXTERNAL.takeIf { isExternal },
         ExtraModifiers.OVERRIDE.takeIf { DescriptorUtils.isOverride(this) }
-    ).toContainer()
+    ).toProperty()
 
-    inline fun <reified D : Documentable> ClassDescriptor.additionalExtras(): PropertyContainer<D> = listOfNotNull(
+    fun ClassDescriptor.additionalExtras() = listOfNotNull(
         ExtraModifiers.DYNAMIC.takeIf { isDynamic() },
         ExtraModifiers.INLINE.takeIf { isInline },
         ExtraModifiers.EXTERNAL.takeIf { isExternal },
         ExtraModifiers.INNER.takeIf { isInner },
         ExtraModifiers.DATA.takeIf { isData },
         ExtraModifiers.OVERRIDE.takeIf { getSuperInterfaces().isNotEmpty() || getSuperClassNotAny() != null }
-    ).toContainer()
+    ).toProperty()
 
-    fun ValueParameterDescriptor.additionalExtras(): PropertyContainer<DParameter> =
+    fun ValueParameterDescriptor.additionalExtras() =
         listOfNotNull(
             ExtraModifiers.DYNAMIC.takeIf { isDynamic() },
             ExtraModifiers.NOINLINE.takeIf { isNoinline },
@@ -473,27 +490,32 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv
             ExtraModifiers.CONST.takeIf { isConst },
             ExtraModifiers.LATEINIT.takeIf { isLateInit },
             ExtraModifiers.VARARG.takeIf { isVararg }
-        ).toContainer()
+        ).toProperty()
 
-    fun TypeParameterDescriptor.additionalExtras(): PropertyContainer<DTypeParameter> =
+    fun TypeParameterDescriptor.additionalExtras() =
         listOfNotNull(
             ExtraModifiers.DYNAMIC.takeIf { isDynamic() },
             ExtraModifiers.REIFIED.takeIf { isReified }
-        ).toContainer()
+        ).toProperty()
 
-    fun PropertyDescriptor.additionalExtras(): PropertyContainer<DProperty> = listOfNotNull(
+    fun PropertyDescriptor.additionalExtras() = listOfNotNull(
         ExtraModifiers.DYNAMIC.takeIf { isDynamic() },
         ExtraModifiers.CONST.takeIf { isConst },
         ExtraModifiers.LATEINIT.takeIf { isLateInit },
         ExtraModifiers.STATIC.takeIf { isJvmStaticInObjectOrClassOrInterface() },
         ExtraModifiers.EXTERNAL.takeIf { isExternal },
         ExtraModifiers.OVERRIDE.takeIf { DescriptorUtils.isOverride(this) }
-    ).toContainer()
+    ).toProperty()
 
-    inline fun <reified D : Documentable> List<ExtraModifiers>.toContainer(
-        container: PropertyContainer<D> = PropertyContainer.empty()
-    ): PropertyContainer<D> =
-        container + AdditionalModifiers(this.toSet())
+    private fun List<ExtraModifiers>.toProperty() =
+        AdditionalModifiers(this.toSet())
+
+    fun DeclarationDescriptor.getAnnotations() = annotations.map { annotation ->
+        Annotations.Annotation(
+            annotation.let { it.annotationClass as DeclarationDescriptor }.let { DRI.from(it) },
+            annotation.allValueArguments.map { (k, v) -> k.asString() to v.value.toString() }.toMap()
+        )
+    }.let(::Annotations)
 
     data class ClassInfo(val supertypes: List<DRI>, val docs: PlatformDependent<DocumentationNode>)
 
diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt
index 2f83d8c0..166a72e3 100644
--- a/plugins/base/src/test/kotlin/model/ClassesTest.kt
+++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt
@@ -402,9 +402,23 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class
         }
     }
 
+    @Test fun annotatedClass() {
+        inlineModelTest(
+            """@Suppress("abc") class Foo() {}"""
+        ) {
+            with((this / "classes" / "Foo").cast<Class>()) {
+                with(extra[Annotations]?.content?.firstOrNull().assertNotNull("annotations")) {
+                    dri.toString() equals "kotlin/Suppress////"
+                    with(params["names"].assertNotNull("param")) {
+                        this equals "[\"abc\"]"
+                    }
+                }
+            }
+        }
+    }
+
     // TODO annotations
-//    @Test
-//    fun annotatedClass() {
+//    @Test fun annotatedClass() {
 //        verifyPackageMember("testdata/classes/annotatedClass.kt", ModelConfig(
 //            analysisPlatform = analysisPlatform,
 //            withKotlinRuntime = true
-- 
cgit