aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt2
-rw-r--r--core/src/main/kotlin/model/documentableProperties.kt4
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt2
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt2
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt1
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt40
-rw-r--r--plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt410
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt45
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt2
-rw-r--r--plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt131
-rw-r--r--plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt91
-rw-r--r--plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt66
-rw-r--r--plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt135
-rw-r--r--plugins/base/src/test/resources/multiplatform/basicMultiplatformTest/jvmMain/kotlin/example/Clock.kt4
14 files changed, 612 insertions, 323 deletions
diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt
index 671d0725..6f42b259 100644
--- a/core/src/main/kotlin/DokkaGenerator.kt
+++ b/core/src/main/kotlin/DokkaGenerator.kt
@@ -85,7 +85,7 @@ class DokkaGenerator(
fun mergeDocumentationModels(
modulesFromPlatforms: List<DModule>,
context: DokkaContext
- ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms, context)
+ ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms)
fun transformDocumentationModelAfterMerge(
documentationModel: DModule,
diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt
index 4eb36599..823b88a0 100644
--- a/core/src/main/kotlin/model/documentableProperties.kt
+++ b/core/src/main/kotlin/model/documentableProperties.kt
@@ -24,4 +24,8 @@ data class ImplementedInterfaces(val interfaces: SourceSetDependent<List<TypeCon
}
override val key: ExtraProperty.Key<Documentable, *> = ImplementedInterfaces
+}
+
+object IsExpectActual: ExtraProperty<WithExpectActual>, ExtraProperty.Key<WithExpectActual, IsExpectActual> {
+ override val key: ExtraProperty.Key<WithExpectActual, IsExpectActual> = this
} \ No newline at end of file
diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt
index c8ae9c02..81c1f470 100644
--- a/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt
+++ b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt
@@ -4,5 +4,5 @@ import org.jetbrains.dokka.model.DModule
import org.jetbrains.dokka.plugability.DokkaContext
interface DocumentableMerger {
- operator fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule
+ operator fun invoke(modules: Collection<DModule>): DModule
} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index 44a532f8..fcea6be9 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -54,7 +54,7 @@ class DokkaBase : DokkaPlugin() {
}
val documentableMerger by extending {
- CoreExtensions.documentableMerger with DefaultDocumentableMerger
+ CoreExtensions.documentableMerger providing ::DefaultDocumentableMerger
}
val deprecatedDocumentableFilter by extending {
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
index c25aa543..e085af1a 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt
@@ -4,6 +4,7 @@ import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProvider
import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation
import org.jetbrains.dokka.base.resolvers.shared.PackageList
+import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.pages.RootPageNode
diff --git a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt
index 096104cc..0269d7a6 100644
--- a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka.base.resolvers.local
+import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.PointingToDeclaration
@@ -26,35 +27,46 @@ open class DokkaLocationProvider(
pageGraphRoot.children.forEach { registerPath(it, emptyList()) }
}
- protected open val pagesIndex: Map<DRI, ContentPage> =
+ protected val pagesIndex: Map<Pair<DRI, DisplaySourceSet>, ContentPage> =
pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
- .flatMap { it.dri.map { dri -> dri to it } }
+ .flatMap { page ->
+ page.dri.flatMap { dri ->
+ page.sourceSets().map { sourceSet -> (dri to sourceSet) to page }
+ }
+ }
.groupingBy { it.first }
- .aggregate { dri, _, (_, page), first ->
- if (first) page else throw AssertionError("Multiple pages associated with dri: $dri")
+ .aggregate { key, _, (_, page), first ->
+ if (first) page else throw AssertionError("Multiple pages associated with key: ${key.first}/${key.second}")
}
- protected open val anchorsIndex: Map<DRI, ContentPage> =
+ protected val anchorsIndex: Map<Pair<DRI, DisplaySourceSet>, ContentPage> =
pageGraphRoot.withDescendants().filterIsInstance<ContentPage>()
.flatMap { page ->
page.content.withDescendants()
.filter { it.extra[SymbolAnchorHint] != null }
.mapNotNull { it.dci.dri.singleOrNull() }
.distinct()
- .map { it to page }
+ .flatMap { dri ->
+ page.sourceSets().map { sourceSet ->
+ (dri to sourceSet) to page
+ }
+ }
}.toMap()
override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) =
pathTo(node, context) + if (!skipExtension) extension else ""
- override fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode?) =
- getLocalLocation(dri, context)
- ?: getLocalLocation(dri.copy(target = PointingToDeclaration), context)
- // Not found in PageGraph, that means it's an external link
- ?: getExternalLocation(dri, sourceSets)
- ?: getExternalLocation(dri.copy(target = PointingToDeclaration), sourceSets)
-
- private fun getLocalLocation(dri: DRI, context: PageNode?): String? =
+ override fun resolve(dri: DRI, sourceSets: Set<DisplaySourceSet>, context: PageNode?): String? =
+ sourceSets.mapNotNull { sourceSet ->
+ val driWithSourceSet = Pair(dri, sourceSet)
+ getLocalLocation(driWithSourceSet, context)
+ ?: getLocalLocation(driWithSourceSet.copy(first = dri.copy(target = PointingToDeclaration)), context)
+ // Not found in PageGraph, that means it's an external link
+ ?: getExternalLocation(dri, sourceSets)
+ ?: getExternalLocation(dri.copy(target = PointingToDeclaration), sourceSets)
+ }.distinct().singleOrNull()
+
+ private fun getLocalLocation(dri: Pair<DRI, DisplaySourceSet>, context: PageNode?): String? =
pagesIndex[dri]?.let { resolve(it, context) }
?: anchorsIndex[dri]?.let { resolve(it, context) + "#$dri" }
diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt
index 17ead667..d556c9cb 100644
--- a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt
+++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt
@@ -1,195 +1,269 @@
package org.jetbrains.dokka.base.transformers.documentables
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.DokkaSourceSetID
import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.model.properties.mergeExtras
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.documentation.DocumentableMerger
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
-internal object DefaultDocumentableMerger : DocumentableMerger {
+internal class DefaultDocumentableMerger(context: DokkaContext) : DocumentableMerger {
+ private val dependencyInfo = context.getDependencyInfo()
- override fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule {
- return modules.reduce { left, right ->
+ override fun invoke(modules: Collection<DModule>): DModule {
+
+ return topologicalSort(modules).reduce { left, right ->
val list = listOf(left, right)
DModule(
name = modules.map { it.name }.distinct().joinToString("|"),
packages = merge(
- list.flatMap { it.packages },
- DPackage::mergeWith
- ),
+ list.flatMap { it.packages }
+ ) { pck1, pck2 -> pck1.mergeWith(pck2) },
documentation = list.map { it.documentation }.flatMap { it.entries }.associate { (k, v) -> k to v },
expectPresentInSet = list.firstNotNullResult { it.expectPresentInSet },
sourceSets = list.flatMap { it.sourceSets }.toSet()
).mergeExtras(left, right)
}
}
-}
-private fun <T : Documentable> merge(elements: List<T>, reducer: (T, T) -> T): List<T> =
- elements.groupingBy { it.dri }
- .reduce { _, left, right -> reducer(left, right) }
- .values.toList()
+ private fun topologicalSort(allModules: Collection<DModule>): List<DModule> {
-private fun <T> mergeExpectActual(
- elements: List<T>,
- reducer: (T, T) -> T
-): List<T> where T : Documentable, T : WithExpectActual {
+ val modulesMap: Map<DokkaSourceSetID, ModuleOfDifferentTranslators> =
+ allModules.groupBy { it.sourceSets.single().sourceSetID }
- fun analyzeExpectActual(sameDriElements: List<T>) = sameDriElements.reduce(reducer)
+ //this returns representation of graph where directed edges are leading from module to modules that depend on it
+ val graph: Map<ModuleOfDifferentTranslators?, List<ModuleOfDifferentTranslators>> = modulesMap.flatMap { (_, module) ->
+ module.first().sourceSets.single().dependentSourceSets.map { sourceSet ->
+ modulesMap[sourceSet] to module
+ }
+ }.groupBy { it.first }.entries
+ .map { it.key to it.value.map { it.second } }
+ .toMap()
- return elements.groupBy { it.dri }.values.map(::analyzeExpectActual)
-}
-fun DPackage.mergeWith(other: DPackage): DPackage = copy(
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- typealiases = merge(typealiases + other.typealiases, DTypeAlias::mergeWith),
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DFunction.mergeWith(other: DFunction): DFunction = copy(
- parameters = merge(this.parameters + other.parameters, DParameter::mergeWith),
- receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- modifier = modifier + other.modifier,
- sourceSets = sourceSets + other.sourceSets,
- generics = merge(generics + other.generics, DTypeParameter::mergeWith)
-).mergeExtras(this, other)
-
-fun DProperty.mergeWith(other: DProperty): DProperty = copy(
- receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- modifier = modifier + other.modifier,
- sourceSets = sourceSets + other.sourceSets,
- getter = getter?.let { g -> other.getter?.let { g.mergeWith(it) } ?: g } ?: other.getter,
- setter = setter?.let { s -> other.setter?.let { s.mergeWith(it) } ?: s } ?: other.setter,
- generics = merge(generics + other.generics, DTypeParameter::mergeWith)
-).mergeExtras(this, other)
-
-fun DClasslike.mergeWith(other: DClasslike): DClasslike = when {
- this is DClass && other is DClass -> mergeWith(other)
- this is DEnum && other is DEnum -> mergeWith(other)
- this is DInterface && other is DInterface -> mergeWith(other)
- this is DObject && other is DObject -> mergeWith(other)
- this is DAnnotation && other is DAnnotation -> mergeWith(other)
- else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot be mergesd with ${other::class.qualifiedName} ${other.name}")
+ val visited = modulesMap.map { it.value to false }.toMap().toMutableMap()
+ val topologicalSortedList: MutableList<ModuleOfDifferentTranslators> = mutableListOf()
+
+ fun dfs(module: ModuleOfDifferentTranslators) {
+ visited[module] = true
+ graph[module]?.forEach { if (!visited[it]!!) dfs(it) }
+ topologicalSortedList.add(0, module)
+ }
+ modulesMap.values.forEach { if (!visited[it]!!) dfs(it) }
+
+ return topologicalSortedList.flatten()
+ }
+
+ private fun DokkaContext.getDependencyInfo()
+ : Map<DokkaConfiguration.DokkaSourceSet, List<DokkaConfiguration.DokkaSourceSet>> {
+
+ fun getDependencies(sourceSet: DokkaConfiguration.DokkaSourceSet): List<DokkaConfiguration.DokkaSourceSet> =
+ listOf(sourceSet) + configuration.sourceSets.filter {
+ it.sourceSetID in sourceSet.dependentSourceSets
+ }.flatMap { getDependencies(it) }
+
+ return configuration.sourceSets.map { it to getDependencies(it) }.toMap()
+ }
+
+ private fun <T : Documentable> merge(elements: List<T>, reducer: (T, T) -> T): List<T> =
+ elements.groupingBy { it.dri }
+ .reduce { _, left, right -> reducer(left, right) }
+ .values.toList()
+
+ private fun <T> mergeExpectActual(
+ elements: List<T>,
+ reducer: (T, T) -> T
+ ): List<T> where T : Documentable, T : WithExpectActual {
+
+ fun analyzeExpectActual(sameDriElements: List<T>) = sameDriElements
+ .partition { it.expectPresentInSet != null }
+ .let { (expects, actuals) ->
+ expects.map { expect ->
+ listOf(expect) + actuals.filter { actual ->
+ dependencyInfo[actual.sourceSets.single()]
+ ?.contains(expect.expectPresentInSet!!)
+ ?: throw IllegalStateException("Cannot resolve expect/actual relation for ${actual.name}")
+ }
+ }.map { it.reduce(reducer) }
+ }
+
+ fun T.isExpectActual(): Boolean =
+ this.safeAs<WithExtraProperties<T>>().let { it != null && it.extra[IsExpectActual] != null }
+
+ fun mergeClashingElements(elements: List<T>) = if(elements.size <= 1) elements else elements.map {
+ when(it) {
+ is DClass -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DObject -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DAnnotation -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DInterface -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DEnum -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DFunction -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ is DProperty -> it.copy(name = "${it.name}(${it.sourceSets.single().analysisPlatform.key})")
+ else -> elements
+ }
+ } as List<T>
+
+ return elements.partition {
+ it.isExpectActual()
+ }.let { (expectActuals, notExpectActuals) ->
+ notExpectActuals.groupBy { it.dri }.values.flatMap(::mergeClashingElements) +
+ expectActuals.groupBy { it.dri }.values.flatMap(::analyzeExpectActual)
+ }
+ }
+
+ fun DPackage.mergeWith(other: DPackage): DPackage = copy(
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ typealiases = merge(typealiases + other.typealiases) { ta1, ta2 -> ta1.mergeWith(ta2) },
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DFunction.mergeWith(other: DFunction): DFunction = copy(
+ parameters = merge(this.parameters + other.parameters) { p1, p2 -> p1.mergeWith(p2) },
+ receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ modifier = modifier + other.modifier,
+ sourceSets = sourceSets + other.sourceSets,
+ generics = merge(generics + other.generics) { tp1, tp2 -> tp1.mergeWith(tp2) },
+ ).mergeExtras(this, other)
+
+ fun DProperty.mergeWith(other: DProperty): DProperty = copy(
+ receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ modifier = modifier + other.modifier,
+ sourceSets = sourceSets + other.sourceSets,
+ getter = getter?.let { g -> other.getter?.let { g.mergeWith(it) } ?: g } ?: other.getter,
+ setter = setter?.let { s -> other.setter?.let { s.mergeWith(it) } ?: s } ?: other.setter,
+ generics = merge(generics + other.generics) { tp1, tp2 -> tp1.mergeWith(tp2) },
+ ).mergeExtras(this, other)
+
+ fun DClasslike.mergeWith(other: DClasslike): DClasslike = when {
+ this is DClass && other is DClass -> mergeWith(other)
+ this is DEnum && other is DEnum -> mergeWith(other)
+ this is DInterface && other is DInterface -> mergeWith(other)
+ this is DObject && other is DObject -> mergeWith(other)
+ this is DAnnotation && other is DAnnotation -> mergeWith(other)
+ else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot be merged with ${other::class.qualifiedName} ${other.name}")
+ }
+
+ fun DClass.mergeWith(other: DClass): DClass = copy(
+ constructors = mergeExpectActual(
+ constructors + other.constructors
+ ) { f1, f2 -> f1.mergeWith(f2) },
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
+ generics = merge(generics + other.generics) { tp1, tp2 -> tp1.mergeWith(tp2) },
+ modifier = modifier + other.modifier,
+ supertypes = supertypes + other.supertypes,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DEnum.mergeWith(other: DEnum): DEnum = copy(
+ entries = merge(entries + other.entries) { ee1, ee2 -> ee1.mergeWith(ee2) },
+ constructors = mergeExpectActual(
+ constructors + other.constructors
+ ) { f1, f2 -> f1.mergeWith(f2) },
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
+ supertypes = supertypes + other.supertypes,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DEnumEntry.mergeWith(other: DEnumEntry): DEnumEntry = copy(
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DObject.mergeWith(other: DObject): DObject = copy(
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ supertypes = supertypes + other.supertypes,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DInterface.mergeWith(other: DInterface): DInterface = copy(
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
+ generics = merge(generics + other.generics) { tp1, tp2 -> tp1.mergeWith(tp2) },
+ supertypes = supertypes + other.supertypes,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DAnnotation.mergeWith(other: DAnnotation): DAnnotation = copy(
+ constructors = mergeExpectActual(
+ constructors + other.constructors
+ ) { f1, f2 -> f1.mergeWith(f2) },
+ functions = mergeExpectActual(functions + other.functions) { f1, f2 -> f1.mergeWith(f2) },
+ properties = mergeExpectActual(properties + other.properties) { p1, p2 -> p1.mergeWith(p2) },
+ classlikes = mergeExpectActual(classlikes + other.classlikes) { c1, c2 -> c1.mergeWith(c2) },
+ companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sources = sources + other.sources,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets,
+ generics = merge(generics + other.generics) { tp1, tp2 -> tp1.mergeWith(tp2) }
+ ).mergeExtras(this, other)
+
+ fun DParameter.mergeWith(other: DParameter): DParameter = copy(
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DTypeParameter.mergeWith(other: DTypeParameter): DTypeParameter = copy(
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
+
+ fun DTypeAlias.mergeWith(other: DTypeAlias): DTypeAlias = copy(
+ documentation = documentation + other.documentation,
+ expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
+ underlyingType = underlyingType + other.underlyingType,
+ visibility = visibility + other.visibility,
+ sourceSets = sourceSets + other.sourceSets
+ ).mergeExtras(this, other)
}
-fun DClass.mergeWith(other: DClass): DClass = copy(
- constructors = mergeExpectActual(
- constructors + other.constructors,
- DFunction::mergeWith
- ),
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
- generics = merge(generics + other.generics, DTypeParameter::mergeWith),
- modifier = modifier + other.modifier,
- supertypes = supertypes + other.supertypes,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DEnum.mergeWith(other: DEnum): DEnum = copy(
- entries = merge(entries + other.entries, DEnumEntry::mergeWith),
- constructors = mergeExpectActual(
- constructors + other.constructors,
- DFunction::mergeWith
- ),
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
- supertypes = supertypes + other.supertypes,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DEnumEntry.mergeWith(other: DEnumEntry): DEnumEntry = copy(
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DObject.mergeWith(other: DObject): DObject = copy(
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- supertypes = supertypes + other.supertypes,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DInterface.mergeWith(other: DInterface): DInterface = copy(
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
- generics = merge(generics + other.generics, DTypeParameter::mergeWith),
- supertypes = supertypes + other.supertypes,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DAnnotation.mergeWith(other: DAnnotation): DAnnotation = copy(
- constructors = mergeExpectActual(
- constructors + other.constructors,
- DFunction::mergeWith
- ),
- functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith),
- properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith),
- classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith),
- companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion,
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sources = sources + other.sources,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets,
- generics = merge(generics + other.generics, DTypeParameter::mergeWith)
-).mergeExtras(this, other)
-
-fun DParameter.mergeWith(other: DParameter): DParameter = copy(
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DTypeParameter.mergeWith(other: DTypeParameter): DTypeParameter = copy(
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
-
-fun DTypeAlias.mergeWith(other: DTypeAlias): DTypeAlias = copy(
- documentation = documentation + other.documentation,
- expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet,
- underlyingType = underlyingType + other.underlyingType,
- visibility = visibility + other.visibility,
- sourceSets = sourceSets + other.sourceSets
-).mergeExtras(this, other)
+private typealias ModuleOfDifferentTranslators = List<DModule>
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
index 8e5a1927..57d4f151 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -12,6 +12,7 @@ import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.Nullable
import org.jetbrains.dokka.model.TypeConstructor
import org.jetbrains.dokka.model.doc.*
+import org.jetbrains.dokka.model.properties.ExtraProperty
import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
@@ -140,6 +141,7 @@ private class DokkaDescriptorVisitor(
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val info = descriptor.resolveClassDescriptionData()
return DInterface(
@@ -156,11 +158,11 @@ private class DokkaDescriptorVisitor(
generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() },
companion = descriptor.companion(driWithPlatform),
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DInterface>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent())
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -168,6 +170,7 @@ private class DokkaDescriptorVisitor(
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val info = descriptor.resolveClassDescriptionData()
@@ -183,11 +186,11 @@ private class DokkaDescriptorVisitor(
supertypes = info.supertypes.toSourceSetDependent(),
documentation = info.docs,
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DObject>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent())
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -195,6 +198,7 @@ private class DokkaDescriptorVisitor(
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val info = descriptor.resolveClassDescriptionData()
return DEnum(
@@ -212,11 +216,11 @@ private class DokkaDescriptorVisitor(
documentation = info.docs,
companion = descriptor.companion(driWithPlatform),
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DEnum>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent())
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -245,6 +249,8 @@ private class DokkaDescriptorVisitor(
fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation {
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
+ val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
return DAnnotation(
dri = driWithPlatform.dri,
@@ -253,12 +259,12 @@ private class DokkaDescriptorVisitor(
classlikes = scope.classlikes(driWithPlatform),
functions = scope.functions(driWithPlatform),
properties = scope.properties(driWithPlatform),
- expectPresentInSet = null,
+ expectPresentInSet = sourceSet.takeIf { isExpect },
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DAnnotation>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations()
- ),
+ ).let { if (isExpect || isActual) it + IsExpectActual else it },
companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) },
visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(),
generics = descriptor.declaredTypeParameters.map { it.toVariantTypeParameter() },
@@ -271,6 +277,7 @@ private class DokkaDescriptorVisitor(
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
val scope = descriptor.unsubstitutedMemberScope
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val info = descriptor.resolveClassDescriptionData()
val actual = descriptor.createSources()
@@ -296,17 +303,18 @@ private class DokkaDescriptorVisitor(
modifier = descriptor.modifier().toSourceSetDependent(),
companion = descriptor.companion(driWithPlatform),
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DClass>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations(),
ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent())
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): DProperty {
val dri = parent.dri.copy(callable = Callable.from(descriptor))
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val actual = descriptor.createSources()
return DProperty(
@@ -333,7 +341,7 @@ private class DokkaDescriptorVisitor(
(descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField()
.toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotationsWithBackingField().toSourceSetDependent().toAnnotations()
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -346,6 +354,7 @@ private class DokkaDescriptorVisitor(
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): DFunction {
val (dri, inheritedFrom) = descriptor.createDRI()
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
val actual = descriptor.createSources()
return DFunction(
@@ -367,11 +376,11 @@ private class DokkaDescriptorVisitor(
modifier = descriptor.modifier().toSourceSetDependent(),
type = descriptor.returnType!!.toBound(),
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DFunction>(
InheritedFunction(inheritedFrom.toSourceSetDependent()),
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations()
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -380,6 +389,7 @@ private class DokkaDescriptorVisitor(
val dri = parent.dri.copy(callable = Callable.from(descriptor, name))
val actual = descriptor.createSources()
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
return DFunction(
dri = dri,
@@ -418,7 +428,7 @@ private class DokkaDescriptorVisitor(
if (descriptor.isPrimary) {
it + PrimaryConstructorExtra
} else it
- }
+ }.let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
@@ -443,6 +453,7 @@ private class DokkaDescriptorVisitor(
val dri = parent.copy(callable = Callable.from(descriptor))
val isGetter = descriptor is PropertyGetterDescriptor
val isExpect = descriptor.isExpect
+ val isActual = descriptor.isActual
fun PropertyDescriptor.asParameter(parent: DRI) =
DParameter(
@@ -490,10 +501,10 @@ private class DokkaDescriptorVisitor(
},
sources = descriptor.createSources(),
sourceSets = setOf(sourceSet),
- extra = PropertyContainer.withAll(
+ extra = PropertyContainer.withAll<DFunction>(
descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(),
descriptor.getAnnotations().toSourceSetDependent().toAnnotations()
- )
+ ).let { if (isExpect || isActual) it + IsExpectActual else it }
)
}
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 3cc77f96..615412f4 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -490,7 +490,7 @@ open class DefaultPageCreator(
header(2, name, kind = kind)
table(kind, extra = extra, styles = emptySet()) {
collection
- .groupBy { it.name }
+ .groupBy { it.name } // This groupBy should probably use LocationProvider
// This hacks displaying actual typealias signatures along classlike ones
.mapValues { if (it.value.any { it is DClasslike }) it.value.filter { it !is DTypeAlias } else it.value }
.toSortedMap(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it })
diff --git a/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt b/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt
new file mode 100644
index 00000000..090196b3
--- /dev/null
+++ b/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt
@@ -0,0 +1,131 @@
+package expectActuals
+
+import org.jetbrains.dokka.pages.ClasslikePageNode
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.Assertions.assertTrue
+
+
+class ExpectActualsTest : AbstractCoreTest() {
+
+ fun PageNode.childrenRec(): List<PageNode> = listOf(this) + children.flatMap { it.childrenRec() }
+
+ @Test
+ fun `two same named expect actual classes`() {
+
+ val configuration = dokkaConfiguration {
+ sourceSets {
+ val common = sourceSet {
+ moduleName = "example"
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf("src/commonMain/kotlin/pageMerger/Test.kt")
+ }
+ val commonJ = sourceSet {
+ moduleName = "example"
+ name = "commonJ"
+ displayName = "commonJ"
+ analysisPlatform = "common"
+ sourceRoots = listOf("src/commonJMain/kotlin/pageMerger/Test.kt")
+ dependentSourceSets = setOf(common.sourceSetID)
+ }
+ val commonN = sourceSet {
+ moduleName = "example"
+ name = "commonN"
+ displayName = "commonN"
+ analysisPlatform = "common"
+ sourceRoots = listOf("src/commonNMain/kotlin/pageMerger/Test.kt")
+ dependentSourceSets = setOf(common.sourceSetID)
+ }
+ val js = sourceSet {
+ moduleName = "example"
+ name = "js"
+ displayName = "js"
+ analysisPlatform = "js"
+ dependentSourceSets = setOf(commonJ.sourceSetID)
+ sourceRoots = listOf("src/jsMain/kotlin/pageMerger/Test.kt")
+ }
+ val jvm = sourceSet {
+ moduleName = "example"
+ name = "jvm"
+ displayName = "jvm"
+ analysisPlatform = "jvm"
+ dependentSourceSets = setOf(commonJ.sourceSetID)
+ sourceRoots = listOf("src/jvmMain/kotlin/pageMerger/Test.kt")
+ }
+ val linuxX64 = sourceSet {
+ moduleName = "example"
+ name = "linuxX64"
+ displayName = "linuxX64"
+ analysisPlatform = "native"
+ dependentSourceSets = setOf(commonN.sourceSetID)
+ sourceRoots = listOf("src/linuxX64Main/kotlin/pageMerger/Test.kt")
+ }
+ val mingwX64 = sourceSet {
+ moduleName = "example"
+ name = "mingwX64"
+ displayName = "mingwX64"
+ analysisPlatform = "native"
+ dependentSourceSets = setOf(commonN.sourceSetID)
+ sourceRoots = listOf("src/mingwX64Main/kotlin/pageMerger/Test.kt")
+ }
+ }
+ }
+
+ testInline(
+ """
+ |/src/commonMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |/src/commonJMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |expect class A
+ |
+ |/src/commonNMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |expect class A
+ |
+ |/src/jsMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |actual class A
+ |
+ |/src/jvmMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |actual class A
+ |
+ |/src/linuxX64/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |actual class A
+ |
+ |/src/mingwX64Main/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |actual class A
+ |
+ """.trimMargin(),
+ configuration
+ ) {
+ pagesTransformationStage = {
+ println(it)
+ val allChildren = it.childrenRec().filterIsInstance<ClasslikePageNode>()
+ val jvmClass = allChildren.filter { it.name == "DoNotMerge(jvm)" }
+ val jsClass = allChildren.filter { it.name == "DoNotMerge(js)" }
+ val noClass = allChildren.filter { it.name == "DoNotMerge" }
+ assertTrue(jvmClass.size == 1) { "There can be only one DoNotMerge(jvm) page" }
+ assertTrue(jvmClass.first().documentable?.sourceSets?.single()?.analysisPlatform?.key == "jvm") { "DoNotMerge(jvm) should have only jvm sources" }
+
+ assertTrue(jsClass.size == 1) { "There can be only one DoNotMerge(js) page" }
+ assertTrue(jsClass.first().documentable?.sourceSets?.single()?.analysisPlatform?.key == "js") { "DoNotMerge(js) should have only js sources" }
+
+ assertTrue(noClass.isEmpty()) { "There can't be any DoNotMerge page" }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt
index 25400ca5..f8eba2fe 100644
--- a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt
+++ b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt
@@ -28,20 +28,33 @@ class LinkableContentTest : AbstractCoreTest() {
val configuration = dokkaConfiguration {
moduleName = "example"
sourceSets {
- sourceSet {
- analysisPlatform = "js"
- sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
+ val common = sourceSet {
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf(Paths.get("$testDataDir/commonMain/kotlin").toString())
+ }
+ val jvmAndJsSecondCommonMain = sourceSet {
+ name = "jvmAndJsSecondCommonMain"
+ displayName = "jvmAndJsSecondCommonMain"
+ analysisPlatform = "common"
+ dependentSourceSets = setOf(common.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmAndJsSecondCommonMain/kotlin").toString())
+ }
+ val js = sourceSet {
name = "js"
+ displayName = "js"
+ analysisPlatform = "js"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jsMain/kotlin").toString())
includes = listOf(Paths.get("$includesDir/include2.md").toString())
}
- sourceSet {
- analysisPlatform = "jvm"
- sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
+ val jvm = sourceSet {
name = "jvm"
+ displayName = "jvm"
+ analysisPlatform = "jvm"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmMain/kotlin").toString())
includes = listOf(Paths.get("$includesDir/include1.md").toString())
}
}
@@ -67,9 +80,25 @@ class LinkableContentTest : AbstractCoreTest() {
moduleName = "example"
sourceSets {
- sourceSet {
+ val common = sourceSet {
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf(Paths.get("$testDataDir/commonMain/kotlin").toString())
+ }
+ val jvmAndJsSecondCommonMain = sourceSet {
+ name = "jvmAndJsSecondCommonMain"
+ displayName = "jvmAndJsSecondCommonMain"
+ analysisPlatform = "common"
+ dependentSourceSets = setOf(common.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmAndJsSecondCommonMain/kotlin").toString())
+ }
+ val js = sourceSet {
+ name = "js"
+ displayName = "js"
analysisPlatform = "js"
- sourceRoots = listOf("$testDataDir/jsMain/kotlin")
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jsMain/kotlin").toString())
sourceLinks = listOf(
SourceLinkDefinitionImpl(
localDirectory = "$testDataDir/jsMain/kotlin",
@@ -77,11 +106,13 @@ class LinkableContentTest : AbstractCoreTest() {
remoteLineSuffix = "#L"
)
)
- name = "js"
}
- sourceSet {
+ val jvm = sourceSet {
+ name = "jvm"
+ displayName = "jvm"
analysisPlatform = "jvm"
- sourceRoots = listOf("$testDataDir/jvmMain/kotlin")
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmMain/kotlin").toString())
sourceLinks = listOf(
SourceLinkDefinitionImpl(
localDirectory = "$testDataDir/jvmMain/kotlin",
@@ -89,7 +120,6 @@ class LinkableContentTest : AbstractCoreTest() {
remoteLineSuffix = "#L"
)
)
- name = "jvm"
}
}
}
@@ -131,16 +161,33 @@ class LinkableContentTest : AbstractCoreTest() {
val configuration = dokkaConfiguration {
moduleName = "example"
sourceSets {
- sourceSet {
- analysisPlatform = "js"
- sourceRoots = listOf("$testDataDir/jsMain/kotlin")
+ val common = sourceSet {
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf(Paths.get("$testDataDir/commonMain/kotlin").toString())
+ }
+ val jvmAndJsSecondCommonMain = sourceSet {
+ name = "jvmAndJsSecondCommonMain"
+ displayName = "jvmAndJsSecondCommonMain"
+ analysisPlatform = "common"
+ dependentSourceSets = setOf(common.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmAndJsSecondCommonMain/kotlin").toString())
+ }
+ val js = sourceSet {
name = "js"
+ displayName = "js"
+ analysisPlatform = "js"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jsMain/kotlin").toString())
samples = listOf("$testDataDir/jsMain/resources/Samples.kt")
}
- sourceSet {
- analysisPlatform = "jvm"
- sourceRoots = listOf("$testDataDir/jvmMain/kotlin")
+ val jvm = sourceSet {
name = "jvm"
+ displayName = "jvm"
+ analysisPlatform = "jvm"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmMain/kotlin").toString())
samples = listOf("$testDataDir/jvmMain/resources/Samples.kt")
}
}
diff --git a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt
index 935b9377..1a57ae02 100644
--- a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt
+++ b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt
@@ -1,5 +1,6 @@
package pageMerger
+import org.jetbrains.dokka.pages.ClasslikePageNode
import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.pages.PageNode
import org.junit.jupiter.api.Assertions.assertTrue
@@ -123,4 +124,69 @@ class PageNodeMergerTest : AbstractCoreTest() {
fun PageNode.childrenRec(): List<PageNode> = listOf(this) + children.flatMap { it.childrenRec() }
+
+ @Test
+ fun `should not be merged`() {
+
+ val configuration = dokkaConfiguration {
+ sourceSets {
+ val common = sourceSet {
+ moduleName = "example"
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf("src/commonMain/kotlin/pageMerger/Test.kt")
+ }
+ val js = sourceSet {
+ moduleName = "example"
+ name = "js"
+ displayName = "js"
+ analysisPlatform = "js"
+ dependentSourceSets = setOf(common.sourceSetID)
+ sourceRoots = listOf("src/jsMain/kotlin/pageMerger/Test.kt")
+ }
+ val jvm = sourceSet {
+ moduleName = "example"
+ name = "jvm"
+ displayName = "jvm"
+ analysisPlatform = "jvm"
+ dependentSourceSets = setOf(common.sourceSetID)
+ sourceRoots = listOf("src/jvmMain/kotlin/pageMerger/Test.kt")
+ }
+ }
+ }
+
+ testInline(
+ """
+ |/src/commonMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |/src/jsMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |annotation class DoNotMerge
+ |
+ |/src/jvmMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |annotation class DoNotMerge
+ """.trimMargin(),
+ configuration
+ ) {
+ pagesTransformationStage = {
+ println(it)
+ val allChildren = it.childrenRec().filterIsInstance<ClasslikePageNode>()
+ val jvmClass = allChildren.filter { it.name == "DoNotMerge(jvm)" }
+ val jsClass = allChildren.filter { it.name == "DoNotMerge(js)" }
+ val noClass = allChildren.filter { it.name == "DoNotMerge" }
+ assertTrue(jvmClass.size == 1) { "There can be only one DoNotMerge(jvm) page" }
+ assertTrue(jvmClass.first().documentable?.sourceSets?.single()?.analysisPlatform?.key == "jvm") { "DoNotMerge(jvm) should have only jvm sources" }
+
+ assertTrue(jsClass.size == 1) { "There can be only one DoNotMerge(js) page" }
+ assertTrue(jsClass.first().documentable?.sourceSets?.single()?.analysisPlatform?.key == "js") { "DoNotMerge(js) should have only js sources" }
+
+ assertTrue(noClass.isEmpty()) { "There can't be any DoNotMerge page" }
+ }
+ }
+ }
}
diff --git a/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt
index 2e8e0ef3..975373b6 100644
--- a/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt
+++ b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt
@@ -10,40 +10,43 @@ import utils.TestOutputWriterPlugin
class DivergentSignatureTest : AbstractCoreTest() {
- @Test
- fun `group { common + jvm + js }`() {
-
- val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath()
-
- val configuration = dokkaConfiguration {
- moduleName = "example"
- sourceSets {
- sourceSet {
- displayName = "js"
- name = "js"
- analysisPlatform = "js"
- sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "jvm"
- name = "jvm"
- analysisPlatform = "jvm"
- sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "common"
- name = "common"
- analysisPlatform = "common"
- sourceRoots = listOf("commonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
+ val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath()
+
+ val configuration = dokkaConfiguration {
+ moduleName = "example"
+ sourceSets {
+ val common = sourceSet {
+ name = "common"
+ displayName = "common"
+ analysisPlatform = "common"
+ sourceRoots = listOf(Paths.get("$testDataDir/commonMain/kotlin").toString())
+ }
+ val jvmAndJsSecondCommonMain = sourceSet {
+ name = "jvmAndJsSecondCommonMain"
+ displayName = "jvmAndJsSecondCommonMain"
+ analysisPlatform = "common"
+ dependentSourceSets = setOf(common.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmAndJsSecondCommonMain/kotlin").toString())
+ }
+ val js = sourceSet {
+ name = "js"
+ displayName = "js"
+ analysisPlatform = "js"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jsMain/kotlin").toString())
+ }
+ val jvm = sourceSet {
+ name = "jvm"
+ displayName = "jvm"
+ analysisPlatform = "jvm"
+ dependentSourceSets = setOf(common.value.sourceSetID, jvmAndJsSecondCommonMain.value.sourceSetID)
+ sourceRoots = listOf(Paths.get("$testDataDir/jvmMain/kotlin").toString())
}
}
+ }
+
+ @Test
+ fun `group { common + jvm + js }`() {
val writerPlugin = TestOutputWriterPlugin()
@@ -55,7 +58,7 @@ class DivergentSignatureTest : AbstractCoreTest() {
val content = writerPlugin.renderedContent("example/example/-clock/get-time.html")
assert(content.count() == 1)
- assert(content.select("[data-filterable-current=example/js example/jvm example/common]").single().brief == "")
+ assert(content.select("[data-filterable-current=example/common example/jvm example/js]").single().brief == "common")
}
}
}
@@ -63,38 +66,6 @@ class DivergentSignatureTest : AbstractCoreTest() {
@Test
fun `group { common + jvm }, group { js }`() {
- val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath()
-
- val configuration = dokkaConfiguration {
- moduleName = "example"
- sourceSets {
- sourceSet {
- displayName = "js"
- name = "js"
- analysisPlatform = "js"
- sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "jvm"
- name = "jvm"
- analysisPlatform = "jvm"
- sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "common"
- name = "common"
- analysisPlatform = "common"
- sourceRoots = listOf("commonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- }
- }
-
val writerPlugin = TestOutputWriterPlugin()
testFromData(
@@ -104,7 +75,7 @@ class DivergentSignatureTest : AbstractCoreTest() {
renderingStage = { _, _ ->
val content = writerPlugin.renderedContent("example/example/-clock/get-times-in-millis.html")
assert(content.count() == 2)
- assert(content.select("[data-filterable-current=example/jvm example/common]").single().brief == "Time in minis")
+ assert(content.select("[data-filterable-current=example/common example/jvm]").single().brief == "Time in minis common")
assert(content.select("[data-filterable-current=example/js]").single().brief == "JS implementation of getTimeInMillis js" )
}
}
@@ -113,38 +84,6 @@ class DivergentSignatureTest : AbstractCoreTest() {
@Test
fun `group { js }, group { jvm }, group { js }`() {
- val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath()
-
- val configuration = dokkaConfiguration {
- moduleName = "example"
- sourceSets {
- sourceSet {
- displayName = "js"
- name = "js"
- analysisPlatform = "js"
- sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "jvm"
- name = "jvm"
- analysisPlatform = "jvm"
- sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- sourceSet {
- displayName = "common"
- name = "common"
- analysisPlatform = "common"
- sourceRoots = listOf("commonMain").map {
- Paths.get("$testDataDir/$it/kotlin").toString()
- }
- }
- }
- }
-
val writerPlugin = TestOutputWriterPlugin()
testFromData(
diff --git a/plugins/base/src/test/resources/multiplatform/basicMultiplatformTest/jvmMain/kotlin/example/Clock.kt b/plugins/base/src/test/resources/multiplatform/basicMultiplatformTest/jvmMain/kotlin/example/Clock.kt
index fec06207..6ad73db7 100644
--- a/plugins/base/src/test/resources/multiplatform/basicMultiplatformTest/jvmMain/kotlin/example/Clock.kt
+++ b/plugins/base/src/test/resources/multiplatform/basicMultiplatformTest/jvmMain/kotlin/example/Clock.kt
@@ -7,6 +7,10 @@ import greeteer.Greeter
*/
actual open class Clock {
actual fun getTime(): String = System.currentTimeMillis().toString()
+
+ /**
+ * Time in minis
+ */
actual fun getTimesInMillis(): String = System.currentTimeMillis().toString()
/**