aboutsummaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/kotlin/Formats/StructuredFormatService.kt12
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt232
-rw-r--r--core/src/main/kotlin/Kotlin/DocumentationBuilder.kt6
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt10
-rw-r--r--core/src/main/kotlin/Model/DocumentationReference.kt53
5 files changed, 288 insertions, 25 deletions
diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt
index ebc9cde6..41c8f29a 100644
--- a/core/src/main/kotlin/Formats/StructuredFormatService.kt
+++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt
@@ -514,15 +514,15 @@ abstract class StructuredOutputBuilder(val to: StringBuilder,
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)
- appendSection("Properties", node.members(NodeKind.Property), omitSamePlatforms = true)
+ appendSection("Enum Values", node.membersOrGroupMembers(NodeKind.EnumItem), sortMembers = false, omitSamePlatforms = true)
+ appendSection("Constructors", node.membersOrGroupMembers(NodeKind.Constructor), omitSamePlatforms = true)
+ appendSection("Properties", node.membersOrGroupMembers(NodeKind.Property), omitSamePlatforms = true)
appendSection("Inherited Properties", node.inheritedMembers(NodeKind.Property))
- appendSection("Functions", node.members(NodeKind.Function), omitSamePlatforms = true)
+ appendSection("Functions", node.membersOrGroupMembers(NodeKind.Function), omitSamePlatforms = true)
appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function))
- appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
+ appendSection("Companion Object Properties", node.membersOrGroupMembers(NodeKind.CompanionObjectProperty), omitSamePlatforms = true)
appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property))
- appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
+ appendSection("Companion Object Functions", node.membersOrGroupMembers(NodeKind.CompanionObjectFunction), omitSamePlatforms = true)
appendSection("Inherited Companion Object Functions", node.inheritedCompanionObjectMembers(NodeKind.Function))
appendSection("Other members", node.members.filter {
it.kind !in setOf(
diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt
index 9de4396b..0c4b3b7e 100644
--- a/core/src/main/kotlin/Generation/DokkaGenerator.kt
+++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt
@@ -2,6 +2,7 @@ package org.jetbrains.dokka
import com.google.inject.Guice
import com.google.inject.Injector
+import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiFile
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.config.JVMConfigurationKeys
+import org.jetbrains.kotlin.config.KotlinSourceRoot
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode
@@ -32,28 +34,34 @@ class DokkaGenerator(val logger: DokkaLogger,
val moduleName: String,
val options: DocumentationOptions) {
- private val documentationModule = DocumentationModule(moduleName)
+ private val documentationModules: MutableList<DocumentationModule> = mutableListOf()
fun generate() {
val sourcesGroupedByPlatform = sources.groupBy { it.platforms.firstOrNull() to it.analysisPlatform }
for ((platformsInfo, roots) in sourcesGroupedByPlatform) {
val (platform, analysisPlatform) = platformsInfo
- appendSourceModule(platform, analysisPlatform, roots)
+
+ val documentationModule = DocumentationModule(moduleName)
+ appendSourceModule(platform, analysisPlatform, roots, documentationModule)
+ documentationModules.add(documentationModule)
}
- documentationModule.prepareForGeneration(options)
+
+ val totalDocumentationModule = DocumentationMerger(documentationModules).merge()
+ totalDocumentationModule.prepareForGeneration(options)
val timeBuild = measureTimeMillis {
logger.info("Generating pages... ")
val outputInjector = Guice.createInjector(DokkaOutputModule(options, logger))
- outputInjector.getInstance(Generator::class.java).buildAll(documentationModule)
+ outputInjector.getInstance(Generator::class.java).buildAll(totalDocumentationModule)
}
logger.info("done in ${timeBuild / 1000} secs")
}
- private fun appendSourceModule(defaultPlatform: String?,
- analysisPlatform: Platform,
- sourceRoots: List<SourceRoot>
-
+ private fun appendSourceModule(
+ defaultPlatform: String?,
+ analysisPlatform: Platform,
+ sourceRoots: List<SourceRoot>,
+ documentationModule: DocumentationModule
) {
val sourcePaths = sourceRoots.map { it.path }
@@ -81,6 +89,12 @@ class DokkaGenerator(val logger: DokkaLogger,
DokkaAnalysisModule(environment, options, defaultPlatformsProvider, documentationModule.nodeRefGraph, logger))
buildDocumentationModule(injector, documentationModule, { isNotSample(it) }, includes)
+ documentationModule.nodeRefGraph.nodeMapView.forEach { (_, node) ->
+ node.addReferenceTo(
+ DocumentationNode(analysisPlatform.key, Content.Empty, NodeKind.Platform),
+ RefKind.Platform
+ )
+ }
val timeAnalyse = System.currentTimeMillis() - startAnalyse
logger.info("done in ${timeAnalyse / 1000} secs")
@@ -214,3 +228,205 @@ fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> {
}
return result
}
+
+class DocumentationMerger(
+ private val documentationModules: List<DocumentationModule>
+) {
+ private val producedNodeRefGraph: NodeReferenceGraph
+ private val signatureMap: Map<DocumentationNode, String>
+
+ init {
+ signatureMap = documentationModules
+ .flatMap { it.nodeRefGraph.nodeMapView.entries }
+ .map { (k, v) -> v to k }
+ .toMap()
+
+ producedNodeRefGraph = NodeReferenceGraph()
+ documentationModules.map { it.nodeRefGraph }
+ .flatMap { it.references }
+ .distinct()
+ .forEach { producedNodeRefGraph.addReference(it) }
+ }
+
+ private fun splitReferencesByKind(
+ source: List<DocumentationReference>,
+ kind: RefKind
+ ): Pair<List<DocumentationReference>, List<DocumentationReference>> =
+ Pair(source.filter { it.kind == kind }, source.filterNot { it.kind == kind })
+
+
+ private fun mergePackageReferences(
+ from: DocumentationNode,
+ packages: List<DocumentationReference>
+ ): List<DocumentationReference> {
+ val packagesByName = packages
+ .map { it.to }
+ .groupBy { it.name }
+
+ val mutableList: MutableList<DocumentationReference> = mutableListOf()
+ for ((name, listOfPackages) in packagesByName) {
+ val producedPackage = mergePackagesWithEqualNames(from, listOfPackages)
+ updatePendingReferences(name, producedPackage)
+
+ mutableList.add(
+ DocumentationReference(from, producedPackage, RefKind.Member)
+ )
+ }
+
+ return mutableList
+ }
+
+ private fun mergePackagesWithEqualNames(
+ from: DocumentationNode,
+ packages: List<DocumentationNode>
+ ): DocumentationNode {
+ val references = packages.flatMap { it.allReferences() }
+
+ val mergedPackage =
+ DocumentationNode(
+ packages.first().name,
+ Content.Empty,
+ NodeKind.Package
+ )
+
+ val mergedReferences = mergeReferences(mergedPackage, references)
+
+ for (packageNode in packages) {
+ mergedPackage.updateContent {
+ for (otherChild in packageNode.content.children) {
+ children.add(otherChild)
+ }
+ }
+ }
+
+ mergedPackage.dropReferences { true } // clear()
+ for (ref in mergedReferences.distinct()) {
+ mergedPackage.addReference(ref)
+ }
+
+ from.append(mergedPackage, RefKind.Member)
+
+ return mergedPackage
+ }
+
+
+ private fun mergeMembers(
+ from: DocumentationNode,
+ refs: List<DocumentationReference>
+ ): List<DocumentationReference> {
+ val membersBySignature: Map<String, List<DocumentationNode>> = refs.map { it.to }
+ .filter { signatureMap.containsKey(it) }
+ .groupBy { signatureMap[it]!! }
+
+ val mergedMembers: MutableList<DocumentationReference> = mutableListOf()
+ for ((signature, members) in membersBySignature) {
+ val newNode = mergeMembersWithEqualSignature(signature, from, members)
+
+ producedNodeRefGraph.register(signature, newNode)
+ updatePendingReferences(signature, newNode)
+ from.append(newNode, RefKind.Member)
+
+ mergedMembers.add(DocumentationReference(from, newNode, RefKind.Member))
+ }
+
+ return mergedMembers
+ }
+
+ private fun mergeMembersWithEqualSignature(
+ signature: String,
+ from: DocumentationNode,
+ refs: List<DocumentationNode>
+ ): DocumentationNode {
+ if (refs.size == 1) {
+ val singleNode = refs.single()
+ singleNode.owner?.let { owner ->
+ singleNode.dropReferences { it.to == owner && it.kind == RefKind.Owner }
+ }
+ return singleNode
+ }
+ val groupNode = DocumentationNode(refs.first().name, Content.Empty, NodeKind.GroupNode)
+ groupNode.appendTextNode(signature, NodeKind.Signature, RefKind.Detail)
+
+ for (node in refs) {
+ if (node != groupNode) {
+ node.owner?.let { owner ->
+ node.dropReferences { it.to == owner && it.kind == RefKind.Owner }
+ from.dropReferences { it.to == node && it.kind == RefKind.Member }
+ }
+ groupNode.append(node, RefKind.Member)
+ }
+ }
+ return groupNode
+ }
+
+
+ private fun mergeReferences(
+ from: DocumentationNode,
+ refs: List<DocumentationReference>
+ ): List<DocumentationReference> {
+ val allRefsToPackages = refs.map { it.to }
+ .all { it.kind == NodeKind.Package }
+
+ if (allRefsToPackages) {
+ return mergePackageReferences(from, refs)
+ }
+
+ val (memberRefs, notMemberRefs) = splitReferencesByKind(refs, RefKind.Member)
+ val mergedMembers = mergeMembers(from, memberRefs)
+
+ return (mergedMembers + notMemberRefs).distinctBy {
+ it.kind to it.to.name
+ }
+ }
+
+
+ private fun updatePendingReferences(
+ signature: String,
+ nodeToUpdate: DocumentationNode
+ ) {
+ producedNodeRefGraph.references.forEach {
+ it.lazyNodeFrom.update(signature, nodeToUpdate)
+ it.lazyNodeTo.update(signature, nodeToUpdate)
+ }
+ }
+
+ private fun NodeResolver.update(signature: String, nodeToUpdate: DocumentationNode) {
+ when (this) {
+ is NodeResolver.BySignature -> update(signature, nodeToUpdate)
+ is NodeResolver.Exact -> update(signature, nodeToUpdate)
+ }
+ }
+
+ private fun NodeResolver.BySignature.update(signature: String, nodeToUpdate: DocumentationNode) {
+ if (signature == nodeToUpdate.name) {
+ nodeMap = producedNodeRefGraph.nodeMapView
+ }
+ }
+
+ private fun NodeResolver.Exact.update(signature: String, nodeToUpdate: DocumentationNode) {
+ exactNode?.let { it ->
+ val equalSignature =
+ it.anyReference { ref -> ref.to.kind == NodeKind.Signature && ref.to.name == signature }
+
+ if (equalSignature) {
+ exactNode = nodeToUpdate
+ }
+ }
+ }
+
+ fun merge(): DocumentationModule {
+ val refs = documentationModules.flatMap {
+ it.allReferences()
+ }
+ val mergedDocumentationModule = DocumentationModule(
+ name = documentationModules.first().name,
+ nodeRefGraph = producedNodeRefGraph
+ )
+
+ mergeReferences(mergedDocumentationModule, refs)
+
+ return mergedDocumentationModule
+ }
+
+
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
index f1b8e3d3..e3675f9d 100644
--- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
+++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt
@@ -1079,7 +1079,7 @@ fun DeclarationDescriptor.signature(): String {
is TypeAliasDescriptor -> DescriptorUtils.getFqName(this).asString()
is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature()
+ is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature() + ":" + returnType?.signature()
is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name
is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name
is ReceiverParameterDescriptor -> containingDeclaration.signature() + "/" + name
@@ -1149,7 +1149,9 @@ fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
fun DocumentationNode.generateAllTypesNode() {
val allTypes = members(NodeKind.Package)
- .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
+ .flatMap { it.members.filter {
+ it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass
+ || (it.kind == NodeKind.GroupNode && it.anyReference { it.to.kind in NodeKind.classLike }) } }
.sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.').toLowerCase() else it.name.toLowerCase() }
val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index a3388031..bdb7cf20 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -134,6 +134,10 @@ open class DocumentationNode(val name: String,
references.add(DocumentationReference(this, to, kind))
}
+ fun addReference(reference: DocumentationReference) {
+ references.add(reference)
+ }
+
fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
references.removeAll(predicate)
}
@@ -159,6 +163,8 @@ open class DocumentationNode(val name: String,
fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single()
fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single()
+ fun anyReference(predicate: (DocumentationReference) -> Boolean): Boolean = references.any(predicate)
+
fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind }
fun allReferences(): Set<DocumentationReference> = references
@@ -167,9 +173,9 @@ open class DocumentationNode(val name: String,
}
}
-class DocumentationModule(name: String, content: Content = Content.Empty)
+class DocumentationModule(name: String, content: Content = Content.Empty, val nodeRefGraph: NodeReferenceGraph = NodeReferenceGraph())
: DocumentationNode(name, content, NodeKind.Module) {
- val nodeRefGraph = NodeReferenceGraph()
+
}
val DocumentationNode.path: List<DocumentationNode>
diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt
index 5db1f05a..9223c17a 100644
--- a/core/src/main/kotlin/Model/DocumentationReference.kt
+++ b/core/src/main/kotlin/Model/DocumentationReference.kt
@@ -25,12 +25,27 @@ enum class RefKind {
data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) {
}
-class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
- val lazyNodeTo: () -> DocumentationNode?,
+sealed class NodeResolver {
+ abstract fun resolve(): DocumentationNode?
+ class BySignature(var signature: String, var nodeMap: Map<String, DocumentationNode>) : NodeResolver() {
+ override fun resolve(): DocumentationNode? {
+ return nodeMap[signature]
+ }
+ }
+
+ class Exact(var exactNode: DocumentationNode?) : NodeResolver() {
+ override fun resolve(): DocumentationNode? {
+ return exactNode
+ }
+ }
+}
+
+class PendingDocumentationReference(val lazyNodeFrom: NodeResolver,
+ val lazyNodeTo: NodeResolver,
val kind: RefKind) {
fun resolve() {
- val fromNode = lazyNodeFrom()
- val toNode = lazyNodeTo()
+ val fromNode = lazyNodeFrom.resolve()
+ val toNode = lazyNodeTo.resolve()
if (fromNode != null && toNode != null) {
fromNode.addReferenceTo(toNode, kind)
}
@@ -39,6 +54,9 @@ class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?,
class NodeReferenceGraph {
private val nodeMap = hashMapOf<String, DocumentationNode>()
+ val nodeMapView: Map<String, DocumentationNode>
+ get() = HashMap(nodeMap)
+
val references = arrayListOf<PendingDocumentationReference>()
fun register(signature: String, node: DocumentationNode) {
@@ -46,15 +64,36 @@ class NodeReferenceGraph {
}
fun link(fromNode: DocumentationNode, toSignature: String, kind: RefKind) {
- references.add(PendingDocumentationReference({ fromNode }, { nodeMap[toSignature] }, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.Exact(fromNode),
+ NodeResolver.BySignature(toSignature, nodeMap),
+ kind
+ ))
}
fun link(fromSignature: String, toNode: DocumentationNode, kind: RefKind) {
- references.add(PendingDocumentationReference({ nodeMap[fromSignature] }, { toNode }, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.BySignature(fromSignature, nodeMap),
+ NodeResolver.Exact(toNode),
+ kind
+ )
+ )
}
fun link(fromSignature: String, toSignature: String, kind: RefKind) {
- references.add(PendingDocumentationReference({ nodeMap[fromSignature] }, { nodeMap[toSignature] }, kind))
+ references.add(
+ PendingDocumentationReference(
+ NodeResolver.BySignature(fromSignature, nodeMap),
+ NodeResolver.BySignature(toSignature, nodeMap),
+ kind
+ )
+ )
+ }
+
+ fun addReference(reference: PendingDocumentationReference) {
+ references.add(reference)
}
fun lookup(signature: String) = nodeMap[signature]