aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2017-03-01 22:26:28 +0300
committerSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2017-03-01 22:26:28 +0300
commitabe161a118d3d7df40ad0e1df8b8adf07773103b (patch)
tree4176768eaaac9eec7240fdcbb954238d790edae8 /core/src
parent1934463c0a2a708acfde371daf0692811f479a7a (diff)
downloaddokka-abe161a118d3d7df40ad0e1df8b8adf07773103b.tar.gz
dokka-abe161a118d3d7df40ad0e1df8b8adf07773103b.tar.bz2
dokka-abe161a118d3d7df40ad0e1df8b8adf07773103b.zip
Correct merging of different type namesake declarations between platforms
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt39
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt90
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt25
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt8
-rw-r--r--core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt10
-rw-r--r--core/src/test/kotlin/format/MarkdownFormatTest.kt10
6 files changed, 139 insertions, 43 deletions
diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
index a8544cca..eac053aa 100644
--- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
+++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt
@@ -34,8 +34,8 @@ open class KotlinWebsiteOutputBuilder(to: StringBuilder,
override fun appendStrikethrough(body: () -> Unit) = wrapInTag("s", body)
- protected fun div(to: StringBuilder, cssClass: String, markdown: Boolean = false, block: () -> Unit) {
- to.append("<div class=\"$cssClass\"")
+ protected fun div(to: StringBuilder, cssClass: String, otherAttributes: String = "", markdown: Boolean = false, block: () -> Unit) {
+ to.append("<div class=\"$cssClass\"$otherAttributes")
if (markdown) to.append(" markdown=\"1\"")
to.append(">")
if (!markdown) insideDiv++
@@ -57,8 +57,8 @@ open class KotlinWebsiteOutputBuilder(to: StringBuilder,
}
}
- override fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) {
- div(to, "overload-group", true) {
+ override fun appendAsOverloadGroup(to: StringBuilder, platforms: Set<String>, block: () -> Unit) {
+ div(to, "overload-group", calculateDataAttributes(platforms), true) {
ensureParagraph()
block()
ensureParagraph()
@@ -147,20 +147,23 @@ open class KotlinWebsiteOutputBuilder(to: StringBuilder,
else -> "identifier"
}
+ fun calculateDataAttributes(platforms: Set<String>): String {
+ fun String.isKotlinVersion() = this.startsWith("Kotlin")
+ fun String.isJREVersion() = this.startsWith("JRE")
+ val kotlinVersion = platforms.singleOrNull(String::isKotlinVersion)
+ val jreVersion = platforms.singleOrNull(String::isJREVersion)
+ val targetPlatforms = platforms.filterNot { it.isKotlinVersion() || it.isJREVersion() }
+
+ val kotlinVersionAttr = kotlinVersion?.let { " data-kotlin-version=\"$it\"" } ?: ""
+ val jreVersionAttr = jreVersion?.let { " data-jre-version=\"$it\"" } ?: ""
+ val platformsAttr = targetPlatforms.ifNotEmpty { " data-platform=\"${targetPlatforms.joinToString()}\"" } ?: ""
+ return "$platformsAttr$kotlinVersionAttr$jreVersionAttr"
+ }
+
override fun appendIndexRow(platforms: Set<String>, block: () -> Unit) {
- if (platforms.isNotEmpty()) {
- fun String.isKotlinVersion() = this.startsWith("Kotlin")
- fun String.isJREVersion() = this.startsWith("JRE")
- val kotlinVersion = platforms.singleOrNull(String::isKotlinVersion)
- val jreVersion = platforms.singleOrNull(String::isJREVersion)
- val targetPlatforms = platforms.filterNot { it.isKotlinVersion() || it.isJREVersion() }
-
- val kotlinVersionAttr = kotlinVersion?.let { " data-kotlin-version=\"$it\"" } ?: ""
- val jreVersionAttr = jreVersion?.let { " data-jre-version=\"$it\"" } ?: ""
- val platformsAttr = targetPlatforms.ifNotEmpty { " data-platform=\"${targetPlatforms.joinToString()}\"" } ?: ""
-
- wrap("<tr$platformsAttr$kotlinVersionAttr$jreVersionAttr>", "</tr>", block)
- } else
+ if (platforms.isNotEmpty())
+ wrap("<tr${calculateDataAttributes(platforms)}>", "</tr>", block)
+ else
appendTableRow(block)
}
@@ -188,7 +191,7 @@ class KotlinWebsiteRunnableSamplesOutputBuilder(to: StringBuilder,
: KotlinWebsiteOutputBuilder(to, location, locationService, languageService, extension, impliedPlatforms) {
override fun appendSampleBlockCode(language: String, imports: () -> Unit, body: () -> Unit) {
- div(to, "sample", true) {
+ div(to, "sample", markdown = true) {
appendBlockCode(language) {
imports()
wrap("\n\nfun main(args: Array<String>) {", "}") {
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index 419e5eeb..b4bb660e 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -185,6 +185,9 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
to: DocumentationNode,
extension: String,
name: (DocumentationNode) -> String = DocumentationNode::name): FormatLink {
+ if (to.owner?.kind == NodeKind.GroupNode)
+ return link(from, to.owner!!, extension, name)
+
return FormatLink(name(to), locationService.relativePathToLocation(from, to))
}
@@ -204,7 +207,7 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
block()
}
- protected open fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) {
+ protected open fun appendAsOverloadGroup(to: StringBuilder, platforms: Set<String>, block: () -> Unit) {
block()
}
@@ -242,16 +245,18 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
appendContent(signatureAsCode)
}
- open inner class PageBuilder(val nodes: Iterable<DocumentationNode>) {
+ open inner class PageBuilder(val nodes: Iterable<DocumentationNode>, val noHeader: Boolean = false) {
open fun build() {
val breakdownByLocation = nodes.groupBy { node ->
node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }
}
for ((path, nodes) in breakdownByLocation) {
- appendBreadcrumbs(path)
- appendLine()
- appendLine()
+ if (!noHeader) {
+ appendBreadcrumbs(path)
+ appendLine()
+ appendLine()
+ }
appendLocation(nodes.filter { it.kind != NodeKind.ExternalClass })
}
}
@@ -268,7 +273,8 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
} else {
val breakdownByName = nodes.groupBy { node -> node.name }
for ((name, items) in breakdownByName) {
- appendHeader { appendText(name) }
+ if (!noHeader)
+ appendHeader { appendText(name) }
appendDocumentation(items)
}
}
@@ -280,9 +286,9 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
if (breakdownBySummary.size == 1) {
formatOverloadGroup(breakdownBySummary.values.single())
} else {
- for ((summary, items) in breakdownBySummary) {
+ for ((_, items) in breakdownBySummary) {
ensureParagraph()
- appendAsOverloadGroup(to) {
+ appendAsOverloadGroup(to, platformsOfItems(items)) {
formatOverloadGroup(items)
}
}
@@ -371,7 +377,7 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
protected fun platformsOfItems(items: List<DocumentationNode>): Set<String> {
val platforms = items.asSequence().map {
when (it.kind) {
- NodeKind.ExternalClass, NodeKind.Package, NodeKind.Module -> platformsOfItems(it.members)
+ NodeKind.ExternalClass, NodeKind.Package, NodeKind.Module, NodeKind.GroupNode -> platformsOfItems(it.members)
else -> it.platformsToShow.toSet()
}
}
@@ -418,8 +424,38 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
}
}
- inner class SingleNodePageBuilder(val node: DocumentationNode)
- : PageBuilder(listOf(node)) {
+ inner class GroupNodePageBuilder(val node: DocumentationNode) : PageBuilder(listOf(node)) {
+
+ override fun build() {
+
+ val breakdownByLocation = node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }
+
+ appendBreadcrumbs(breakdownByLocation)
+ appendLine()
+ appendLine()
+ appendHeader { appendText(node.name) }
+
+ fun DocumentationNode.priority(): Int = when (kind) {
+ NodeKind.TypeAlias -> 1
+ NodeKind.Class -> 2
+ else -> 3
+ }
+
+ for (member in node.members.sortedBy(DocumentationNode::priority)) {
+ ensureParagraph()
+ appendAsOverloadGroup(to, platformsOfItems(listOf(member))) {
+ formatSubNodeOfGroup(member)
+ }
+ }
+ }
+
+ fun formatSubNodeOfGroup(member: DocumentationNode) {
+ SingleNodePageBuilder(member, true).build()
+ }
+ }
+
+ inner class SingleNodePageBuilder(val node: DocumentationNode, noHeader: Boolean = false)
+ : PageBuilder(listOf(node), noHeader) {
override fun build() {
super.build()
@@ -429,11 +465,19 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
return
}
+ fun DocumentationNode.membersOrGroupMembers(predicate: (DocumentationNode) -> Boolean): List<DocumentationNode> {
+ return members.filter(predicate) + members(NodeKind.GroupNode).flatMap { it.members.filter(predicate) }
+ }
+
+ fun DocumentationNode.membersOrGroupMembers(kind: NodeKind): List<DocumentationNode> {
+ return membersOrGroupMembers { it.kind == kind }
+ }
+
appendSection("Packages", node.members(NodeKind.Package), platformsBasedOnMembers = true)
- appendSection("Types", node.members.filter { it.kind in NodeKind.classLike && it.kind != NodeKind.TypeAlias && it.kind != NodeKind.AnnotationClass && it.kind != NodeKind.Exception })
- appendSection("Annotations", node.members(NodeKind.AnnotationClass))
- appendSection("Exceptions", node.members(NodeKind.Exception))
- appendSection("Type Aliases", node.members(NodeKind.TypeAlias))
+ appendSection("Types", node.membersOrGroupMembers { it.kind in NodeKind.classLike && it.kind != NodeKind.TypeAlias && it.kind != NodeKind.AnnotationClass && it.kind != NodeKind.Exception })
+ appendSection("Annotations", node.membersOrGroupMembers(NodeKind.AnnotationClass))
+ appendSection("Exceptions", node.membersOrGroupMembers(NodeKind.Exception))
+ appendSection("Type Aliases", node.membersOrGroupMembers(NodeKind.TypeAlias))
appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass))
appendSection("Enum Values", node.members(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
appendSection("Constructors", node.members(NodeKind.Constructor), omitSamePlatforms = true)
@@ -462,7 +506,8 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
NodeKind.CompanionObjectFunction,
NodeKind.ExternalClass,
NodeKind.EnumItem,
- NodeKind.AllTypes
+ NodeKind.AllTypes,
+ NodeKind.GroupNode
)
})
@@ -586,14 +631,11 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
override fun appendNodes(nodes: Iterable<DocumentationNode>) {
val singleNode = nodes.singleOrNull()
- if (singleNode != null) {
- if (singleNode.kind == NodeKind.AllTypes) {
- AllTypesNodeBuilder(singleNode).build()
- } else {
- SingleNodePageBuilder(singleNode).build()
- }
- } else {
- PageBuilder(nodes).build()
+ when (singleNode?.kind) {
+ NodeKind.AllTypes -> AllTypesNodeBuilder(singleNode).build()
+ NodeKind.GroupNode -> GroupNodePageBuilder(singleNode).build()
+ null -> PageBuilder(nodes).build()
+ else -> SingleNodePageBuilder(singleNode).build()
}
}
}
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index fcb86d53..299ad477 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -278,11 +278,36 @@ class DocumentationBuilder
return null
}
+ fun createGroupNode(signature: String, nodes: List<DocumentationNode>) = (nodes.find { it.kind == NodeKind.GroupNode } ?:
+ DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode).apply {
+ appendTextNode(signature, NodeKind.Signature, RefKind.Detail)
+ })
+ .also { groupNode ->
+ nodes.forEach { node ->
+ if (node != groupNode) {
+ node.owner?.let { owner ->
+ node.dropReferences { it.to == owner && it.kind == RefKind.Owner }
+ owner.dropReferences { it.to == node && it.kind == RefKind.Member }
+ owner.append(groupNode, RefKind.Member)
+ }
+ groupNode.append(node, RefKind.Member)
+ }
+ }
+ }
+
+
fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
if (descriptor.isGenerated() || !descriptor.isDocumented(options)) return
val existingNode = refGraph.lookup(descriptor.signature())
if (existingNode != null) {
+ if (existingNode.kind == NodeKind.TypeAlias && descriptor is ClassDescriptor
+ || existingNode.kind == NodeKind.Class && descriptor is TypeAliasDescriptor) {
+ val node = createGroupNode(descriptor.signature(), listOf(existingNode, descriptor.build()))
+ register(descriptor, node)
+ return
+ }
+
existingNode.updatePlatforms(descriptor)
if (descriptor is ClassDescriptor) {
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index caacac14..c38a6a9f 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -56,7 +56,9 @@ enum class NodeKind {
* A note which is rendered once on a page documenting a group of overloaded functions.
* Needs to be generated equally on all overloads.
*/
- OverloadGroupNote;
+ OverloadGroupNote,
+
+ GroupNode;
companion object {
val classLike = setOf(Class, Interface, Enum, AnnotationClass, Exception, Object, TypeAlias)
@@ -106,6 +108,10 @@ open class DocumentationNode(val name: String,
references.add(DocumentationReference(this, to, kind))
}
+ fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
+ references.removeAll(predicate)
+ }
+
fun addAllReferencesFrom(other: DocumentationNode) {
references.addAll(other.references)
}
diff --git a/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
index 2d86ba5b..9565263f 100644
--- a/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
+++ b/core/src/test/kotlin/format/KotlinWebSiteFormatTest.kt
@@ -1,6 +1,7 @@
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.*
+import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.junit.Test
class KotlinWebSiteFormatTest {
@@ -23,6 +24,15 @@ class KotlinWebSiteFormatTest {
verifyMultiplatformPackage(module, "dataTags")
}
+ @Test fun dataTagsInGroupNode() {
+ val path = "dataTagsInGroupNode"
+ val module = buildMultiplePlatforms(path)
+ verifyModelOutput(module, ".md", "testdata/format/website/$path/multiplatform.kt") { model, output ->
+ kwsService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members.find { it.kind == NodeKind.GroupNode }.singletonOrEmptyList())
+ }
+ verifyMultiplatformPackage(module, path)
+ }
+
private fun verifyKWSNodeByName(fileName: String, name: String) {
verifyOutput("testdata/format/website/$fileName.kt", ".md", format = "kotlin-website") { model, output ->
kwsService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members.filter { it.name == name })
diff --git a/core/src/test/kotlin/format/MarkdownFormatTest.kt b/core/src/test/kotlin/format/MarkdownFormatTest.kt
index 04c2dc62..2753e18d 100644
--- a/core/src/test/kotlin/format/MarkdownFormatTest.kt
+++ b/core/src/test/kotlin/format/MarkdownFormatTest.kt
@@ -1,6 +1,7 @@
package org.jetbrains.dokka.tests
import org.jetbrains.dokka.*
+import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.junit.Test
class MarkdownFormatTest {
@@ -304,6 +305,15 @@ class MarkdownFormatTest {
verifyMultiplatformPackage(module, path)
}
+ @Test fun multiplePlatformsGroupNode() {
+ val path = "multiplatform/groupNode"
+ val module = buildMultiplePlatforms(path)
+ verifyModelOutput(module, ".md", "testdata/format/$path/multiplatform.kt") { model, output ->
+ markdownService.createOutputBuilder(output, tempLocation).appendNodes(model.members.single().members.find { it.kind == NodeKind.GroupNode }.singletonOrEmptyList())
+ }
+ verifyMultiplatformPackage(module, path)
+ }
+
private fun buildMultiplePlatforms(path: String): DocumentationModule {
val module = DocumentationModule("test")
val options = DocumentationOptions("", "html", generateIndexPages = false)