aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Generation
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/Generation')
-rw-r--r--core/src/main/kotlin/Generation/DokkaGenerator.kt232
1 files changed, 224 insertions, 8 deletions
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