Support companion members
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
index ae2af33..5148097 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
@@ -87,23 +87,41 @@
}
}
+val DocumentationNode.companion get() = members(NodeKind.Object).find { it.details(NodeKind.Modifier).any { it.name == "companion" } }
-fun DocumentationNode.signatureForAnchor(logger: DokkaLogger): String = when (kind) {
- NodeKind.Function, NodeKind.Constructor -> buildString {
+fun DocumentationNode.signatureForAnchor(logger: DokkaLogger): String {
+
+ fun StringBuilder.appendReceiverIfSo() {
detailOrNull(NodeKind.Receiver)?.let {
append("(")
append(it.detail(NodeKind.Type).qualifiedNameFromType())
append(").")
}
- append(name)
- details(NodeKind.Parameter).joinTo(this, prefix = "(", postfix = ")") { it.detail(NodeKind.Type).qualifiedNameFromType() }
}
- NodeKind.Property ->
- "$name:${detail(NodeKind.Type).qualifiedNameFromType()}"
- NodeKind.TypeParameter, NodeKind.Parameter -> owner!!.signatureForAnchor(logger) + "/" + name
- else -> "Not implemented signatureForAnchor $this".also { logger.warn(it) }
-}
+ return when (kind) {
+ NodeKind.Function, NodeKind.Constructor, NodeKind.CompanionObjectFunction -> buildString {
+ if (kind == NodeKind.CompanionObjectFunction) {
+ append("Companion.")
+ }
+ appendReceiverIfSo()
+ append(name)
+ details(NodeKind.Parameter).joinTo(this, prefix = "(", postfix = ")") { it.detail(NodeKind.Type).qualifiedNameFromType() }
+ }
+ NodeKind.Property, NodeKind.CompanionObjectProperty -> buildString {
+ if (kind == NodeKind.CompanionObjectProperty) {
+ append("Companion.")
+ }
+ appendReceiverIfSo()
+ append(name)
+ append(":")
+ append(detail(NodeKind.Type).qualifiedNameFromType())
+ }
+ NodeKind.TypeParameter, NodeKind.Parameter -> owner!!.signatureForAnchor(logger) + "/" + name
+ else -> "Not implemented signatureForAnchor $this".also { logger.warn(it) }
+ }
+
+}
fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8")
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
index 740b278..0c95a41 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
@@ -202,8 +202,8 @@
summaryNodeGroup(node.members(NodeKind.Property), "Top-level properties summary") { propertyLikeSummaryRow(it) }
- fullDocs(node.members(NodeKind.Function), { h2 { +"Top-level functions" } }) { memberDocs(it) }
- fullDocs(node.members(NodeKind.Property), { h2 { +"Top-level properties" } }) { memberDocs(it) }
+ fullDocs(node.members(NodeKind.Function), "Top-level functions") { memberDocs(it) }
+ fullDocs(node.members(NodeKind.Property), "Top-level properties") { memberDocs(it) }
}
)
@@ -316,42 +316,62 @@
h2 { +"Summary" }
- fun DocumentationNode.isFunction() = kind == NodeKind.Function || kind == NodeKind.CompanionObjectFunction
- fun DocumentationNode.isProperty() = kind == NodeKind.Property || kind == NodeKind.CompanionObjectProperty
+ val isCompanion = node.details(NodeKind.Modifier).any { it.name == "companion" }
+ val hasMeaningfulCompanion = !isCompanion && node.companion != null
fun DocumentationNode.thisTypeExtension() = detail(NodeKind.Receiver).detail(NodeKind.Type).links.any { it == node }
- val functionsToDisplay = node.members.filter(DocumentationNode::isFunction)
- val properties = node.members.filter(DocumentationNode::isProperty)
- val inheritedFunctionsByReceiver = node.inheritedMembers.filter(DocumentationNode::isFunction).groupBy { it.owner!! }
- val inheritedPropertiesByReceiver = node.inheritedMembers.filter(DocumentationNode::isProperty).groupBy { it.owner!! }
- val (extensions, inheritedExtensions) = node.extensions.partition {
- it.thisTypeExtension()
- }
+ val functionKind = if (!isCompanion) NodeKind.Function else NodeKind.CompanionObjectFunction
+ val propertyKind = if (!isCompanion) NodeKind.Property else NodeKind.CompanionObjectProperty
+
+ fun DocumentationNode.isFunction() = kind == functionKind
+ fun DocumentationNode.isProperty() = kind == propertyKind
+
+ val functions = node.members(functionKind)
+ val properties = node.members(propertyKind)
+ val inheritedFunctionsByReceiver = node.inheritedMembers(functionKind).groupBy { it.owner!! }
+ val inheritedPropertiesByReceiver = node.inheritedMembers(propertyKind).groupBy { it.owner!! }
+
+
+ val originalExtensions = if (!isCompanion) node.extensions else node.owner!!.extensions
+ val (extensions, inheritedExtensions) = originalExtensions.partition { it.thisTypeExtension() }
val extensionFunctions = extensions.filter(DocumentationNode::isFunction).groupBy { it.owner!! }
val extensionProperties = extensions.filter(DocumentationNode::isProperty).groupBy { it.owner!! }
val inheritedExtensionFunctions = inheritedExtensions.filter(DocumentationNode::isFunction).groupBy { it.owner!! }
val inheritedExtensionProperties = inheritedExtensions.filter(DocumentationNode::isProperty).groupBy { it.owner!! }
+ val companionFunctions = node.members(NodeKind.CompanionObjectFunction)
+ val companionProperties = node.members(NodeKind.CompanionObjectProperty)
+
summaryNodeGroup(node.members.filter { it.kind in NodeKind.classLike }, "Nested classes", headerAsRow = true) { nestedClassSummaryRow(it) }
summaryNodeGroup(node.members(NodeKind.Constructor), "Constructors", headerAsRow = true) { functionLikeSummaryRow(it) }
- summaryNodeGroup(functionsToDisplay, "Functions", headerAsRow = true) { functionLikeSummaryRow(it) }
+ summaryNodeGroup(functions, "Functions", headerAsRow = true) { functionLikeSummaryRow(it) }
+ if (!isCompanion) {
+ summaryNodeGroup(companionFunctions, "Companion functions", headerAsRow = true) { functionLikeSummaryRow(it) }
+ }
summaryNodeGroup(inheritedFunctionsByReceiver.entries, "Inherited functions", headerAsRow = true) { inheritRow(it) { functionLikeSummaryRow(it) } }
summaryNodeGroup(extensionFunctions.entries, "Extension functions", headerAsRow = true) { extensionRow(it) { functionLikeSummaryRow(it) } }
summaryNodeGroup(inheritedExtensionFunctions.entries, "Inherited extension functions", headerAsRow = true) { extensionRow(it) { functionLikeSummaryRow(it) } }
summaryNodeGroup(properties, "Properties", headerAsRow = true) { propertyLikeSummaryRow(it) }
+ if (!isCompanion) {
+ summaryNodeGroup(companionProperties, "Companion properties", headerAsRow = true) { propertyLikeSummaryRow(it) }
+ }
summaryNodeGroup(inheritedPropertiesByReceiver.entries, "Inherited properties", headerAsRow = true) { inheritRow(it) { propertyLikeSummaryRow(it) } }
summaryNodeGroup(extensionProperties.entries, "Extension properties", headerAsRow = true) { extensionRow(it) { propertyLikeSummaryRow(it) } }
summaryNodeGroup(inheritedExtensionProperties.entries, "Inherited extension properties", headerAsRow = true) { extensionRow(it) { propertyLikeSummaryRow(it) } }
- fullDocs(node.members(NodeKind.Constructor), { h2 { +"Constructors" } }) { memberDocs(it) }
- fullDocs(functionsToDisplay, { h2 { +"Functions" } }) { memberDocs(it) }
- fullDocs(properties, { h2 { +"Properties" } }) { memberDocs(it) }
+ fullDocs(node.members(NodeKind.Constructor), "Constructors") { memberDocs(it) }
+ fullDocs(functions, "Functions") { memberDocs(it) }
+ fullDocs(properties, "Properties") { memberDocs(it) }
+ if (!isCompanion && !hasMeaningfulCompanion) {
+ fullDocs(companionFunctions, "Companion functions") { memberDocs(it) }
+ fullDocs(companionProperties, "Companion properties") { memberDocs(it) }
+ }
}
)
@@ -431,11 +451,13 @@
private fun FlowContent.fullDocs(
nodes: List<DocumentationNode>,
- header: FlowContent.() -> Unit,
+ header: String,
renderNode: FlowContent.(DocumentationNode) -> Unit
) {
if (nodes.none()) return
- header()
+ h2 {
+ +header
+ }
for (node in nodes) {
renderNode(node)
}
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt
index 6447d9c..f9cbd04 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt
@@ -3,6 +3,7 @@
import com.google.inject.Inject
import com.google.inject.name.Named
import org.jetbrains.dokka.*
+import org.jetbrains.dokka.NodeKind.Companion.classLike
import org.jetbrains.kotlin.preprocessor.mkdirsOrFail
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import java.io.BufferedWriter
@@ -40,7 +41,16 @@
in NodeKind.classLike -> tryGetContainerUri(node)?.resolve("#")
in NodeKind.memberLike -> {
val owner = if (node.owner?.kind != NodeKind.ExternalClass) node.owner else node.owner?.owner
- tryGetMainUri(owner!!)?.resolveInPage(node)
+ if (owner!!.kind in classLike &&
+ (node.kind == NodeKind.CompanionObjectProperty || node.kind == NodeKind.CompanionObjectFunction) &&
+ owner.companion != null
+ ) {
+ val signature = node.detail(NodeKind.Signature)
+ val originalFunction = owner.companion!!.members.first { it.detailOrNull(NodeKind.Signature)?.name == signature.name }
+ tryGetMainUri(owner.companion!!)?.resolveInPage(originalFunction)
+ } else {
+ tryGetMainUri(owner)?.resolveInPage(node)
+ }
}
NodeKind.TypeParameter, NodeKind.Parameter -> node.path.asReversed().drop(1).firstNotNullResult(this::tryGetMainUri)?.resolveInPage(node)
NodeKind.AllTypes -> tryGetContainerUri(node.owner!!)?.resolve("classes.html")