package org.jetbrains.dokka.model import com.intellij.psi.PsiNamedElement import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.load.kotlin.toSourceElement abstract class Documentable { abstract val name: String? abstract val dri: DRI abstract val children: List abstract val documentation: SourceSetDependent abstract val sourceSets: Set abstract val expectPresentInSet: SourceSetData? override fun toString(): String = "${javaClass.simpleName}($dri)" override fun equals(other: Any?) = other is Documentable && this.dri == other.dri // TODO: https://github.com/Kotlin/dokka/pull/667#discussion_r382555806 override fun hashCode() = dri.hashCode() } typealias SourceSetDependent = Map interface WithExpectActual { val sources: SourceSetDependent } interface WithScope { val functions: List val properties: List val classlikes: List } interface WithVisibility { val visibility: SourceSetDependent } interface WithType { val type: Bound } interface WithAbstraction { val modifier: SourceSetDependent } sealed class Modifier(val name: String) sealed class KotlinModifier(name: String) : Modifier(name) { object Abstract : KotlinModifier("abstract") object Open : KotlinModifier("open") object Final : KotlinModifier("final") object Sealed : KotlinModifier("sealed") object Empty : KotlinModifier("") } sealed class JavaModifier(name: String) : Modifier(name) { object Abstract : JavaModifier("abstract") object Final : JavaModifier("final") object Empty : JavaModifier("") } interface WithCompanion { val companion: DObject? } interface WithConstructors { val constructors: List } interface WithGenerics { val generics: List } interface WithSupertypes { val supertypes: SourceSetDependent> } interface Callable : WithVisibility, WithType, WithAbstraction, WithExpectActual { val receiver: DParameter? } sealed class DClasslike : Documentable(), WithScope, WithVisibility, WithExpectActual data class DModule( override val name: String, val packages: List, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData? = null, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val dri: DRI = DRI.topLevel override val children: List get() = packages override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DPackage( override val dri: DRI, override val functions: List, override val properties: List, override val classlikes: List, val typealiases: List, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData? = null, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val name = dri.packageName.orEmpty() override val children: List get() = (properties + functions + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DClass( override val dri: DRI, override val name: String, override val constructors: List, override val functions: List, override val properties: List, override val classlikes: List, override val sources: SourceSetDependent, override val visibility: SourceSetDependent, override val companion: DObject?, override val generics: List, override val supertypes: SourceSetDependent>, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val modifier: SourceSetDependent, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DEnum( override val dri: DRI, override val name: String, val entries: List, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, override val companion: DObject?, override val constructors: List, override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties { override val children: List get() = (entries + functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DEnumEntry( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val functions: List, override val properties: List, override val classlikes: List, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DFunction( override val dri: DRI, override val name: String, val isConstructor: Boolean, val parameters: List, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val visibility: SourceSetDependent, override val type: Bound, override val generics: List, override val receiver: DParameter?, override val modifier: SourceSetDependent, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithGenerics, WithExtraProperties { override val children: List get() = parameters override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DInterface( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, override val companion: DObject?, override val generics: List, override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DObject( override val name: String?, override val dri: DRI, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithSupertypes, WithExtraProperties { override val children: List get() = (functions + properties + classlikes) as List override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DAnnotation( override val name: String, override val dri: DRI, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val functions: List, override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, override val companion: DObject?, override val constructors: List, override val generics: List, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithExtraProperties, WithGenerics { override val children: List get() = (functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DProperty( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sources: SourceSetDependent, override val visibility: SourceSetDependent, override val type: Bound, override val receiver: DParameter?, val setter: DFunction?, val getter: DFunction?, override val modifier: SourceSetDependent, override val sourceSets: Set, override val generics: List, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), Callable, WithExtraProperties, WithGenerics { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } // TODO: treat named Parameters and receivers differently data class DParameter( override val dri: DRI, override val name: String?, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, val type: Bound, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DTypeParameter( override val dri: DRI, override val name: String, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, val bounds: List, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } data class DTypeAlias( override val dri: DRI, override val name: String, override val type: Bound, val underlyingType: SourceSetDependent, override val visibility: SourceSetDependent, override val documentation: SourceSetDependent, override val expectPresentInSet: SourceSetData?, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithType, WithVisibility, WithExtraProperties { override val children: List get() = emptyList() override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } sealed class Projection sealed class Bound : Projection() data class OtherParameter(val declarationDRI: DRI, val name: String) : Bound() object Star : Projection() data class TypeConstructor( val dri: DRI, val projections: List, val modifier: FunctionModifiers = FunctionModifiers.NONE ) : Bound() data class Nullable(val inner: Bound) : Bound() data class Variance(val kind: Kind, val inner: Bound) : Projection() { enum class Kind { In, Out } } data class PrimitiveJavaType(val name: String) : Bound() object Void : Bound() object JavaObject : Bound() object Dynamic : Bound() data class UnresolvedBound(val name: String): Bound() enum class FunctionModifiers { NONE, FUNCTION, EXTENSION } private fun String.shorten(maxLength: Int) = lineSequence().first().let { if (it.length != length || it.length > maxLength) it.take(maxLength - 3) + "..." else it } fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? = if (predicate(this)) { this } else { this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull() } fun Documentable.withDescendants(): Sequence { return sequence { yield(this@withDescendants) children.forEach { child -> yieldAll(child.withDescendants()) } } } sealed class Visibility(val name: String) sealed class KotlinVisibility(name: String) : Visibility(name) { object Public : KotlinVisibility("public") object Private : KotlinVisibility("private") object Protected : KotlinVisibility("protected") object Internal : KotlinVisibility("internal") } sealed class JavaVisibility(name: String) : Visibility(name) { object Public : JavaVisibility("public") object Private : JavaVisibility("private") object Protected : JavaVisibility("protected") object Default : JavaVisibility("") } fun SourceSetDependent?.orEmpty(): SourceSetDependent = this ?: emptyMap() interface DocumentableSource { val path: String } class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource { override val path = descriptor.toSourceElement.containingFile.toString() } class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource { override val path = psi.containingFile.virtualFile.path }