diff options
author | Andrzej Ratajczak <andrzej.ratajczak98@gmail.com> | 2020-06-25 14:22:51 +0200 |
---|---|---|
committer | Andrzej Ratajczak <32793002+BarkingBad@users.noreply.github.com> | 2020-09-08 12:52:59 +0200 |
commit | a1f8efc30b4421ce371b02b747bbeac24fafd7ba (patch) | |
tree | 7dba1baab9ad4d8db7436e65c7e9c26618a07c89 /plugins/base/src | |
parent | 270ff58ea44b7700be45062f75bbc7fd50d183eb (diff) | |
download | dokka-a1f8efc30b4421ce371b02b747bbeac24fafd7ba.tar.gz dokka-a1f8efc30b4421ce371b02b747bbeac24fafd7ba.tar.bz2 dokka-a1f8efc30b4421ce371b02b747bbeac24fafd7ba.zip |
Changed way of merging documentables to avoid exception on merging documentables of different types. Minor javadoc fixes. Changed constructor names. Add handling same name pages clash for different platforms
Diffstat (limited to 'plugins/base/src')
11 files changed, 606 insertions, 321 deletions
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() /** |