diff options
-rw-r--r-- | .idea/compiler.xml | 10 | ||||
-rw-r--r-- | core/src/main/kotlin/Generation/DocumentationMerger.kt | 235 | ||||
-rw-r--r-- | core/src/main/kotlin/Generation/DokkaGenerator.kt | 71 | ||||
-rw-r--r-- | core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt | 81 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt | 75 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/DocumentationBuilder.kt | 914 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt | 3 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/DocumentationNode.kt | 339 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/DocumentationReference.kt | 115 | ||||
-rw-r--r-- | core/src/main/kotlin/Utilities/DokkaModules.kt | 3 | ||||
-rw-r--r-- | core/src/main/kotlin/links/DRI.kt | 2 |
11 files changed, 307 insertions, 1541 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 71547e0e..d3328b68 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -52,6 +52,8 @@ <module name="dokka.runners.maven-plugin.test" target="1.8" /> <module name="fatjar_main" target="1.8" /> <module name="fatjar_test" target="1.8" /> + <module name="gradle-integration-tests.org.jetbrains.dokka.gradle-integration-tests.main" target="1.8" /> + <module name="gradle-integration-tests.org.jetbrains.dokka.gradle-integration-tests.test" target="1.8" /> <module name="gradle-integration-tests_main" target="1.8" /> <module name="gradle-integration-tests_test" target="1.8" /> <module name="gradle-plugin_main" target="1.8" /> @@ -70,6 +72,8 @@ <module name="org.jetbrains.dokka.cli.test" target="1.8" /> <module name="org.jetbrains.dokka.core.main" target="1.8" /> <module name="org.jetbrains.dokka.core.test" target="1.8" /> + <module name="org.jetbrains.dokka.coreDependencies.main" target="1.8" /> + <module name="org.jetbrains.dokka.coreDependencies.test" target="1.8" /> <module name="org.jetbrains.dokka.fatjar.main" target="1.8" /> <module name="org.jetbrains.dokka.fatjar.test" target="1.8" /> <module name="org.jetbrains.dokka.gradle-integration-tests.main" target="1.8" /> @@ -78,8 +82,14 @@ <module name="org.jetbrains.dokka.gradle-plugin.test" target="1.8" /> <module name="org.jetbrains.dokka.integration.main" target="1.8" /> <module name="org.jetbrains.dokka.integration.test" target="1.8" /> + <module name="org.jetbrains.dokka.javadoc8.main" target="1.8" /> + <module name="org.jetbrains.dokka.javadoc8.test" target="1.8" /> <module name="org.jetbrains.dokka.maven-plugin.main" target="1.8" /> <module name="org.jetbrains.dokka.maven-plugin.test" target="1.8" /> + <module name="org.jetbrains.dokka.plugins.main" target="1.8" /> + <module name="org.jetbrains.dokka.plugins.test" target="1.8" /> + <module name="org.jetbrains.dokka.testApi.main" target="1.8" /> + <module name="org.jetbrains.dokka.testApi.test" target="1.8" /> </bytecodeTargetLevel> </component> </project>
\ No newline at end of file diff --git a/core/src/main/kotlin/Generation/DocumentationMerger.kt b/core/src/main/kotlin/Generation/DocumentationMerger.kt deleted file mode 100644 index 53dc23a9..00000000 --- a/core/src/main/kotlin/Generation/DocumentationMerger.kt +++ /dev/null @@ -1,235 +0,0 @@ -package org.jetbrains.dokka.Generation - -import org.jetbrains.dokka.* - -class DocumentationMerger( - private val documentationModules: List<DocumentationModule>, - val logger: DokkaLogger -) { - private val producedNodeRefGraph: NodeReferenceGraph = NodeReferenceGraph() - private val signatureMap: Map<DocumentationNode, String> - private val oldToNewNodeMap: MutableMap<DocumentationNode, DocumentationNode> = mutableMapOf() - - init { - if (documentationModules.groupBy { it.name }.size > 1) { - throw IllegalArgumentException("Modules should have similar names: ${documentationModules.joinToString(", ") {it.name}}") - } - - signatureMap = documentationModules - .flatMap { it.nodeRefGraph.nodeMapView.entries } - .associate { (k, v) -> v to k } - - - documentationModules.map { it.nodeRefGraph } - .flatMap { it.references } - .forEach { producedNodeRefGraph.addReference(it) } - } - - private fun mergePackageReferences( - from: DocumentationNode, - packages: List<DocumentationReference> - ): List<DocumentationReference> { - val packagesByName = packages - .map { it.to } - .groupBy { it.name } - - val resultReferences = mutableListOf<DocumentationReference>() - for ((name, listOfPackages) in packagesByName) { - try { - val producedPackage = mergePackagesWithEqualNames(name, from, listOfPackages) - updatePendingReferences() - - resultReferences.add( - DocumentationReference(from, producedPackage, RefKind.Member) - ) - } catch (t: Throwable) { - val entries = listOfPackages.joinToString(",") { "references:${it.allReferences().size}" } - throw Error("Failed to merge package $name from $from with entries $entries. ${t.message}", t) - } - } - - return resultReferences - } - - private fun mergePackagesWithEqualNames( - name: String, - from: DocumentationNode, - packages: List<DocumentationNode> - ): DocumentationNode { - val mergedPackage = DocumentationNode(name, Content.Empty, NodeKind.Package) - - for (contentToAppend in packages.map { it.content }.distinct()) { - mergedPackage.updateContent { - for (otherChild in contentToAppend.children) { - children.add(otherChild) - } - } - } - - for (node in packages) { - oldToNewNodeMap[node] = mergedPackage - } - - val references = packages.flatMap { it.allReferences() } - val mergedReferences = mergeReferences(mergedPackage, references) - for (ref in mergedReferences) { - if (ref.kind == RefKind.Owner) { - continue - } - mergedPackage.addReference(ref) - } - - from.append(mergedPackage, RefKind.Member) - - return mergedPackage - } - - private fun mergeMemberGroupBy(it: DocumentationNode): String { - val signature = signatureMap[it] - - if (signature != null) { - return signature - } - - logger.error("Failed to find signature for $it in \n${it.allReferences().joinToString { "\n ${it.kind} ${it.to}" }}") - return "<ERROR>" - } - - private fun mergeMemberReferences( - from: DocumentationNode, - refs: List<DocumentationReference> - ): List<DocumentationReference> { - val membersBySignature: Map<String, List<DocumentationNode>> = refs.map { it.to } - .groupBy(this::mergeMemberGroupBy) - - val mergedMembers: MutableList<DocumentationReference> = mutableListOf() - for ((signature, members) in membersBySignature) { - val newNode = mergeMembersWithEqualSignature(signature, members) - - producedNodeRefGraph.register(signature, newNode) - updatePendingReferences() - from.append(newNode, RefKind.Member) - - mergedMembers.add(DocumentationReference(from, newNode, RefKind.Member)) - } - - return mergedMembers - } - - private fun mergeMembersWithEqualSignature( - signature: String, - nodes: List<DocumentationNode> - ): DocumentationNode { - require(nodes.isNotEmpty()) - - val singleNode = nodes.singleOrNull() - if (singleNode != null) { - singleNode.dropReferences { it.kind == RefKind.Owner } - return singleNode - } - - // Specialization processing - // Given (Common, JVM, JRE6, JS) and (JVM, JRE6) and (JVM, JRE7) - // Sorted: (JVM, JRE6), (JVM, JRE7), (Common, JVM, JRE6, JS) - // Should output: (JVM, JRE6), (JVM, JRE7), (Common, JS) - // Should not remove first platform - val nodesSortedByPlatformCount = nodes.sortedBy { it.platforms.size } - val allPlatforms = mutableSetOf<String>() - nodesSortedByPlatformCount.forEach { node -> - node.platforms - .filterNot { allPlatforms.add(it) } - .filter { it != node.platforms.first() } - .forEach { platform -> - node.dropReferences { it.kind == RefKind.Platform && it.to.name == platform } - } - } - - // TODO: Quick and dirty fox for merging extensions for external classes. Fix this probably in StructuredFormatService - // TODO: while refactoring documentation model - - val groupNode = if(nodes.first().kind == NodeKind.ExternalClass){ - DocumentationNode(nodes.first().name, Content.Empty, NodeKind.ExternalClass) - } else { - DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode) - } - groupNode.appendTextNode(signature, NodeKind.Signature, RefKind.Detail) - - for (node in nodes) { - node.dropReferences { it.kind == RefKind.Owner } - groupNode.append(node, RefKind.Origin) - node.append(groupNode, RefKind.TopLevelPage) - - oldToNewNodeMap[node] = groupNode - } - - if (groupNode.kind == NodeKind.ExternalClass){ - val refs = nodes.flatMap { it.allReferences() }.filter { it.kind != RefKind.Owner && it.kind != RefKind.TopLevelPage } - refs.forEach { - if (it.kind != RefKind.Link) { - it.to.dropReferences { ref -> ref.kind == RefKind.Owner } - it.to.append(groupNode, RefKind.Owner) - } - groupNode.append(it.to, it.kind) - } - } - - // if nodes are classes, nested members should be also merged and - // inserted at the same level with class - if (nodes.all { it.kind in NodeKind.classLike }) { - val members = nodes.flatMap { it.allReferences() }.filter { it.kind == RefKind.Member } - val mergedMembers = mergeMemberReferences(groupNode, members) - - for (ref in mergedMembers) { - if (ref.kind == RefKind.Owner) { - continue - } - - groupNode.append(ref.to, RefKind.Member) - } - } - - return groupNode - } - - - private fun mergeReferences( - from: DocumentationNode, - refs: List<DocumentationReference> - ): List<DocumentationReference> { - val (refsToPackages, otherRefs) = refs.partition { it.to.kind == NodeKind.Package } - val mergedPackages = mergePackageReferences(from, refsToPackages) - - val (refsToMembers, refsNotToMembers) = otherRefs.partition { it.kind == RefKind.Member } - val mergedMembers = mergeMemberReferences(from, refsToMembers) - - return mergedPackages + mergedMembers + refsNotToMembers - } - - fun merge(): DocumentationModule { - val mergedDocumentationModule = DocumentationModule( - name = documentationModules.first().name, - content = documentationModules.first().content, - nodeRefGraph = producedNodeRefGraph - ) - - val refs = documentationModules.flatMap { - it.allReferences() - } - mergeReferences(mergedDocumentationModule, refs) - - return mergedDocumentationModule - } - - private fun updatePendingReferences() { - for (ref in producedNodeRefGraph.references) { - ref.lazyNodeFrom.update() - ref.lazyNodeTo.update() - } - } - - private fun NodeResolver.update() { - if (this is NodeResolver.Exact && exactNode in oldToNewNodeMap) { - exactNode = oldToNewNodeMap[exactNode]!! - } - } -}
\ No newline at end of file diff --git a/core/src/main/kotlin/Generation/DokkaGenerator.kt b/core/src/main/kotlin/Generation/DokkaGenerator.kt index 90d7cfcc..51d70fbd 100644 --- a/core/src/main/kotlin/Generation/DokkaGenerator.kt +++ b/core/src/main/kotlin/Generation/DokkaGenerator.kt @@ -7,9 +7,7 @@ import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiFile import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager -import org.jetbrains.dokka.Generation.DocumentationMerger import org.jetbrains.dokka.Utilities.DokkaAnalysisModule -import org.jetbrains.dokka.Utilities.DokkaOutputModule import org.jetbrains.dokka.Utilities.DokkaRunModule import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation @@ -24,12 +22,13 @@ import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer import org.jetbrains.kotlin.resolve.TopDownAnalysisMode import org.jetbrains.kotlin.utils.PathUtil import java.io.File -import kotlin.system.measureTimeMillis -class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration, - val logger: DokkaLogger) { +class DokkaGenerator( + val dokkaConfiguration: DokkaConfiguration, + val logger: DokkaLogger +) { - private val documentationModules: MutableList<DocumentationModule> = mutableListOf() + private val documentationModules: MutableList<DocumentationNodes.Module> = mutableListOf() private val globalInjector = Guice.createInjector(DokkaRunModule(dokkaConfiguration)) @@ -37,26 +36,15 @@ class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration, for (pass in passesConfigurations) { - val documentationModule = DocumentationModule(pass.moduleName) + val documentationModule = DocumentationNodes.Module(pass.moduleName) appendSourceModule(pass, documentationModule) documentationModules.add(documentationModule) } - - val totalDocumentationModule = DocumentationMerger(documentationModules, logger).merge() - totalDocumentationModule.prepareForGeneration(dokkaConfiguration) - - val timeBuild = measureTimeMillis { - logger.info("Generating pages... ") - val outputInjector = globalInjector.createChildInjector(DokkaOutputModule(dokkaConfiguration, logger)) - val instance = outputInjector.getInstance(Generator::class.java) - instance.buildAll(totalDocumentationModule) - } - logger.info("done in ${timeBuild / 1000} secs") } private fun appendSourceModule( passConfiguration: DokkaConfiguration.PassConfiguration, - documentationModule: DocumentationModule + documentationModule: DocumentationNodes.Module ) = with(passConfiguration) { val sourcePaths = passConfiguration.sourceRoots.map { it.path } @@ -84,9 +72,15 @@ class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration, } val injector = globalInjector.createChildInjector( - DokkaAnalysisModule(environment, dokkaConfiguration, defaultPlatformsProvider, documentationModule.nodeRefGraph, passConfiguration, logger)) + DokkaAnalysisModule(environment, dokkaConfiguration, defaultPlatformsProvider, passConfiguration, logger) + ) - buildDocumentationModule(injector, documentationModule, { isNotSample(it, passConfiguration.samples) }, includes) + buildDocumentationModule( + injector, + documentationModule, + { isNotSample(it, passConfiguration.samples) }, + includes + ) val timeAnalyse = System.currentTimeMillis() - startAnalyse logger.info("done in ${timeAnalyse / 1000} secs") @@ -118,7 +112,7 @@ class DokkaGenerator(val dokkaConfiguration: DokkaConfiguration, return environment } - private fun isNotSample(file: PsiFile, samples: List<String>): Boolean { + private fun isNotSample(file: PsiFile, samples: List<String>): Boolean { val sourceFile = File(file.virtualFile!!.path) return samples.none { sample -> val canonicalSample = File(sample).canonicalPath @@ -145,10 +139,12 @@ class DokkaMessageCollector(val logger: DokkaLogger) : MessageCollector { override fun hasErrors() = seenErrors } -fun buildDocumentationModule(injector: Injector, - documentationModule: DocumentationModule, - filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true }, - includes: List<String> = listOf()) { +fun buildDocumentationModule( + injector: Injector, + documentationModule: DocumentationNodes.Module, + filesToDocumentFilter: (PsiFile) -> Boolean = { file -> true }, + includes: List<String> = listOf() +) { val coreEnvironment = injector.getInstance(KotlinCoreEnvironment::class.java) val fragmentFiles = coreEnvironment.getSourceFiles().filter(filesToDocumentFilter) @@ -158,25 +154,20 @@ fun buildDocumentationModule(injector: Injector, analyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, fragmentFiles) val fragments = fragmentFiles.mapNotNull { resolutionFacade.resolveSession.getPackageFragment(it.packageFqName) } - .distinct() + .distinct() val packageDocs = injector.getInstance(PackageDocs::class.java) for (include in includes) { packageDocs.parse(include, fragments) } - if (documentationModule.content.isEmpty()) { - documentationModule.updateContent { - for (node in packageDocs.moduleContent.children) { - append(node) - } - } - } parseJavaPackageDocs(packageDocs, coreEnvironment) with(injector.getInstance(DocumentationBuilder::class.java)) { - documentationModule.appendFragments(fragments, packageDocs.packageContent, - injector.getInstance(PackageDocumentationBuilder::class.java)) + documentationModule.appendFragments( + fragments, + injector.getInstance(PackageDocumentationBuilder::class.java) + ) propagateExtensionFunctionsToSubclasses(fragments, resolutionFacade) } @@ -189,8 +180,8 @@ fun buildDocumentationModule(injector: Injector, fun parseJavaPackageDocs(packageDocs: PackageDocs, coreEnvironment: KotlinCoreEnvironment) { val contentRoots = coreEnvironment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) - ?.filterIsInstance<JavaSourceRoot>() - ?.map { it.file } + ?.filterIsInstance<JavaSourceRoot>() + ?.map { it.file } ?: listOf() contentRoots.forEach { root -> root.walkTopDown().filter { it.name == "overview.html" }.forEach { @@ -202,8 +193,8 @@ fun parseJavaPackageDocs(packageDocs: PackageDocs, coreEnvironment: KotlinCoreEn fun KotlinCoreEnvironment.getJavaSourceFiles(): List<PsiJavaFile> { val sourceRoots = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) - ?.filterIsInstance<JavaSourceRoot>() - ?.map { it.file } + ?.filterIsInstance<JavaSourceRoot>() + ?.map { it.file } ?: listOf() val result = arrayListOf<PsiJavaFile>() diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt index 3b368329..d3fc7048 100644 --- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt +++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtModifierListOwner fun getSignature(element: PsiElement?) = when(element) { @@ -55,30 +54,33 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { private val passConfiguration: DokkaConfiguration.PassConfiguration private val refGraph: NodeReferenceGraph private val docParser: JavaDocumentationParser + private val documentationBuilder: DocumentationBuilder @Inject constructor( - passConfiguration: DokkaConfiguration.PassConfiguration, + documentationBuilder: DocumentationBuilder, refGraph: NodeReferenceGraph, logger: DokkaLogger, signatureProvider: ElementSignatureProvider, externalDocumentationLinkResolver: ExternalDocumentationLinkResolver ) { - this.passConfiguration = passConfiguration + this.passConfiguration = documentationBuilder.passConfiguration + this.documentationBuilder = documentationBuilder this.refGraph = refGraph this.docParser = JavadocParser(refGraph, logger, signatureProvider, externalDocumentationLinkResolver) } - constructor(passConfiguration: DokkaConfiguration.PassConfiguration, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) { - this.passConfiguration = passConfiguration + constructor(documentationBuilder: DocumentationBuilder, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) { + this.passConfiguration = documentationBuilder.passConfiguration this.refGraph = refGraph this.docParser = docParser + this.documentationBuilder = documentationBuilder } override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) { if (skipFile(file) || file.classes.all { skipElement(it) }) { return } - val packageNode = findOrCreatePackageNode(module, file.packageName, emptyMap(), refGraph) + val packageNode = documentationBuilder.findOrCreatePackageNode(module, file.packageName, emptyMap(), refGraph) appendClasses(packageNode, file.classes) } @@ -108,7 +110,7 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { } fun nodeForElement(element: PsiNamedElement, - kind: NodeKind, + kind: DocumentationNodes, name: String = element.name ?: "<anonymous>", register: Boolean = false): DocumentationNode { val (docComment, deprecatedContent) = docParser.parseDocumentation(element) @@ -125,14 +127,6 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { } } } - if (deprecatedContent != null) { - val deprecationNode = DocumentationNode("", deprecatedContent, NodeKind.Modifier) - node.append(deprecationNode, RefKind.Deprecation) - } - if (element is PsiDocCommentOwner && element.isDeprecated && node.deprecation == null) { - val deprecationNode = DocumentationNode("", Content.of(ContentText("Deprecated")), NodeKind.Modifier) - node.append(deprecationNode, RefKind.Deprecation) - } return node } @@ -182,15 +176,15 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { fun PsiClass.build(): DocumentationNode { val kind = when { - isAnnotationType -> NodeKind.AnnotationClass - isInterface -> NodeKind.Interface - isEnum -> NodeKind.Enum - isException() -> NodeKind.Exception - else -> NodeKind.Class + isAnnotationType -> DocumentationNodes.AnnotationClass + isInterface -> DocumentationNodes.Interface + isEnum -> DocumentationNodes.Enum + isException() -> DocumentationNodes.Exception + else -> DocumentationNodes.Class } val node = nodeForElement(this, kind, register = isAnnotationType) superTypes.filter { !ignoreSupertype(it) }.forEach { - node.appendType(it, NodeKind.Supertype) + node.appendType(it, DocumentationNodes.Supertype) val superClass = it.resolve() if (superClass != null) { link(superClass, node, RefKind.Inheritor) @@ -239,13 +233,13 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { "\"" + StringUtil.escapeStringCharacters(value) + "\"" else -> value.toString() } - append(DocumentationNode(text, Content.Empty, NodeKind.Value), RefKind.Detail) + append(DocumentationNode(text, Content.Empty, DocumentationNodes.Value), RefKind.Detail) } } - private fun PsiField.nodeKind(): NodeKind = when { - this is PsiEnumConstant -> NodeKind.EnumItem - else -> NodeKind.Field + private fun PsiField.nodeKind(): DocumentationNodes = when { + this is PsiEnumConstant -> DocumentationNodes.EnumItem + else -> DocumentationNodes.Field } fun PsiMethod.build(): DocumentationNode { @@ -261,24 +255,21 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { return node } - private fun PsiMethod.nodeKind(): NodeKind = when { - isConstructor -> NodeKind.Constructor - else -> NodeKind.Function + private fun PsiMethod.nodeKind(): DocumentationNodes = when { + isConstructor -> DocumentationNodes.Constructor + else -> DocumentationNodes.Function } fun PsiParameter.build(): DocumentationNode { - val node = nodeForElement(this, NodeKind.Parameter) + val node = nodeForElement(this, DocumentationNodes.Parameter::class) node.appendType(type) - if (type is PsiEllipsisType) { - node.appendTextNode("vararg", NodeKind.Modifier, RefKind.Detail) - } return node } fun PsiTypeParameter.build(): DocumentationNode { - val node = nodeForElement(this, NodeKind.TypeParameter) - extendsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) } - implementsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) } + val node = nodeForElement(this, DocumentationNodes.TypeParameter) + extendsListTypes.forEach { node.appendType(it, DocumentationNodes.UpperBound) } + implementsListTypes.forEach { node.appendType(it, DocumentationNodes.UpperBound) } return node } @@ -287,27 +278,27 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { PsiModifier.MODIFIERS.forEach { if (modifierList.hasExplicitModifier(it)) { - appendTextNode(it, NodeKind.Modifier) + appendTextNode(it, DocumentationNodes.Modifier) } } } - fun DocumentationNode.appendType(psiType: PsiType?, kind: NodeKind = NodeKind.Type) { + fun DocumentationNode.appendType(psiType: PsiType?, kind: DocumentationNodes = DocumentationNodes.Type) { if (psiType == null) { return } append(psiType.build(kind), RefKind.Detail) } - fun PsiType.build(kind: NodeKind = NodeKind.Type): DocumentationNode { + fun PsiType.build(kind: DocumentationNodes = DocumentationNodes.Type): DocumentationNode { val name = mapTypeName(this) val node = DocumentationNode(name, Content.Empty, kind) if (this is PsiClassType) { - node.appendDetails(parameters) { build(NodeKind.Type) } + node.appendDetails(parameters) { build(DocumentationNodes.Type) } link(node, resolve()) } if (this is PsiArrayType && this !is PsiEllipsisType) { - node.append(componentType.build(NodeKind.Type), RefKind.Detail) + node.append(componentType.build(DocumentationNodes.Type), RefKind.Detail) } return node } @@ -316,7 +307,7 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { val existing = refGraph.lookup(getSignature(psiClass)!!) if (existing != null) return existing val new = psiClass.build() - val packageNode = findOrCreatePackageNode(null, (psiClass.containingFile as PsiJavaFile).packageName, emptyMap(), refGraph) + val packageNode = documentation. findOrCreatePackageNode(null, (psiClass.containingFile as PsiJavaFile).packageName, emptyMap(), refGraph) packageNode.append(new, RefKind.Member) return new } @@ -327,20 +318,20 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { is KtLightAbstractAnnotation -> clsDelegate else -> this } - val node = DocumentationNode(qualifiedName?.substringAfterLast(".") ?: "<?>", Content.Empty, NodeKind.Annotation) + val node = DocumentationNodes.Annotation(qualifiedName?.substringAfterLast(".") ?: "<?>") val psiClass = original.nameReferenceElement?.resolve() as? PsiClass if (psiClass != null && psiClass.isAnnotationType) { node.append(lookupOrBuildClass(psiClass), RefKind.Link) } parameterList.attributes.forEach { - val parameter = DocumentationNode(it.name ?: "value", Content.Empty, NodeKind.Parameter) + val parameter = DocumentationNodes.Parameter(it.name ?: "value", this.extractDescriptor()) val value = it.value if (value != null) { val valueText = (value as? PsiLiteralExpression)?.value as? String ?: value.text - val valueNode = DocumentationNode(valueText, Content.Empty, NodeKind.Value) + val valueNode = DocumentationNode(valueText, Content.Empty, DocumentationNodes.Value) parameter.append(valueNode, RefKind.Detail) } - node.append(parameter, RefKind.Detail) + node.append(parameter, RefKind.Detail)m } return node } diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt index ce20aeec..7c9f2d15 100644 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt @@ -30,20 +30,28 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.source.PsiSourceElement class DescriptorDocumentationParser - @Inject constructor(val options: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val resolutionFacade: DokkaResolutionFacade, - val refGraph: NodeReferenceGraph, - val sampleService: SampleProcessingService, - val signatureProvider: KotlinElementSignatureProvider, - val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver -) -{ - fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Content = - parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first +@Inject constructor( + val options: DokkaConfiguration.PassConfiguration, + val logger: DokkaLogger, + val linkResolver: DeclarationLinkResolver, + val resolutionFacade: DokkaResolutionFacade, + val refGraph: NodeReferenceGraph, + val sampleService: SampleProcessingService, + val signatureProvider: KotlinElementSignatureProvider, + val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver +) { + fun parseDocumentation( + descriptor: DeclarationDescriptor, + inline: Boolean = false, + isDefaultNoArgConstructor: Boolean = false + ): Content = + parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first - fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> { + fun parseDocumentationAndDetails( + descriptor: DeclarationDescriptor, + inline: Boolean = false, + isDefaultNoArgConstructor: Boolean = false + ): Pair<Content, (DocumentationNode) -> Unit> { if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) { return parseJavadoc(descriptor) } @@ -51,8 +59,8 @@ class DescriptorDocumentationParser val kdoc = descriptor.findKDoc() ?: findStdlibKDoc(descriptor) if (kdoc == null) { if (options.effectivePackageOptions(descriptor.fqNameSafe).reportUndocumented && !descriptor.isDeprecated() && - descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && - descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) { + descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && + descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) { logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}") } return Content.Empty to { node -> } @@ -62,7 +70,7 @@ class DescriptorDocumentationParser (PsiTreeUtil.getParentOfType(kdoc, KDoc::class.java)?.context as? KtDeclaration) ?.takeIf { it != descriptor.original.sourcePsi() } ?.resolveToDescriptorIfAny() - ?: descriptor + ?: descriptor var kdocText = if (isDefaultNoArgConstructor) { getConstructorTagContent(descriptor) ?: kdoc.getContent() @@ -74,7 +82,11 @@ class DescriptorDocumentationParser } val tree = parseMarkdown(kdocText) val linkMap = LinkMap.buildLinkMap(tree.node, kdocText) - val content = buildContent(tree, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, inline) + val content = buildContent( + tree, + LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, + inline + ) if (kdoc is KDocSection) { val tags = kdoc.getTags() tags.forEach { @@ -87,7 +99,10 @@ class DescriptorDocumentationParser val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName()) val sectionContent = it.getContent() val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo(markdownNode, section, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }) + buildInlineContentTo( + markdownNode, + section, + LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }) } } } @@ -102,7 +117,7 @@ class DescriptorDocumentationParser } - private fun DeclarationDescriptor.isSuppressWarning() : Boolean { + private fun DeclarationDescriptor.isSuppressWarning(): Boolean { val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!)) return if (suppressAnnotation != null) { @Suppress("UNCHECKED_CAST") @@ -126,11 +141,12 @@ class DescriptorDocumentationParser } if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") { val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassifierDescriptors( - FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE) + FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE + ) anyClassDescriptors.forEach { val anyMethod = (it as ClassDescriptor).getMemberScope(listOf()) - .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name } - .single() + .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name } + .single() val kdoc = anyMethod.findKDoc() if (kdoc != null) { return kdoc @@ -145,17 +161,12 @@ class DescriptorDocumentationParser val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi if (psi is PsiDocCommentOwner) { val parseResult = JavadocParser( - refGraph, - logger, - signatureProvider, - externalDocumentationLinkResolver + refGraph, + logger, + signatureProvider, + externalDocumentationLinkResolver ).parseDocumentation(psi as PsiNamedElement) - return parseResult.content to { node -> - parseResult.deprecatedContent?.let { - val deprecationNode = DocumentationNode("", it, NodeKind.Modifier) - node.append(deprecationNode, RefKind.Deprecation) - } - } + return parseResult.content to { node -> } } return Content.Empty to { node -> } } diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt index 3168e033..6d258564 100644 --- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt @@ -1,61 +1,51 @@ package org.jetbrains.dokka import com.google.inject.Inject -import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiJavaFile import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration -import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotated -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType -import org.jetbrains.kotlin.idea.util.makeNotNullable -import org.jetbrains.kotlin.idea.util.toFuzzyType import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.source.PsiSourceElement -import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.util.supertypesWithAny +import kotlin.reflect.KClass import com.google.inject.name.Named as GuiceNamed -private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor, - extensionReceiverDescriptor: DeclarationDescriptor, - allFqNames: Collection<FqName>): Boolean { - val extensionFunctionPackage = DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java) - val extensionReceiverPackage = DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java) +private fun isExtensionForExternalClass( + extensionFunctionDescriptor: DeclarationDescriptor, + extensionReceiverDescriptor: DeclarationDescriptor, + allFqNames: Collection<FqName> +): Boolean { + val extensionFunctionPackage = + DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java) + val extensionReceiverPackage = + DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java) return extensionFunctionPackage != null && extensionReceiverPackage != null && extensionFunctionPackage.fqName != extensionReceiverPackage.fqName && extensionReceiverPackage.fqName !in allFqNames } interface PackageDocumentationBuilder { - fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>, - allFqNames: Collection<FqName>) + fun buildPackageDocumentation( + documentationBuilder: DocumentationBuilder, + packageName: FqName, + packageNode: DocumentationNodes.Package, + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName> + ) } interface DefaultPlatformsProvider { @@ -67,121 +57,33 @@ val ignoredSupertypes = setOf( ) class DocumentationBuilder -@Inject constructor(val resolutionFacade: DokkaResolutionFacade, - val descriptorDocumentationParser: DescriptorDocumentationParser, - val passConfiguration: DokkaConfiguration.PassConfiguration, - val refGraph: NodeReferenceGraph, - val platformNodeRegistry: PlatformNodeRegistry, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val defaultPlatformsProvider: DefaultPlatformsProvider) { - val boringBuiltinClasses = setOf( - "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean", - "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any") - val knownModifiers = setOf( - KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD, - KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD, - KtTokens.OVERRIDE_KEYWORD, KtTokens.INLINE_KEYWORD) - - fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) { - refGraph.link(node, descriptor.signature(), kind) - } - - fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: RefKind) { - if (fromDescriptor != null && toDescriptor != null) { - refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind) - } - } - - fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) { - refGraph.register(descriptor.signature(), node) - } - - fun <T> nodeForDescriptor( - descriptor: T, - kind: NodeKind, - external: Boolean = false - ): DocumentationNode where T : DeclarationDescriptor, T : Named { - val (doc, callback) = - if (external) { - Content.Empty to { node -> } - } else { - descriptorDocumentationParser.parseDocumentationAndDetails( - descriptor, - kind == NodeKind.Parameter - ) - } - val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor) - node.appendSignature(descriptor) - callback(node) - return node - } - - private fun DocumentationNode.withModifiers(descriptor: DeclarationDescriptor): DocumentationNode { - if (descriptor is MemberDescriptor) { - appendVisibility(descriptor) - if (descriptor !is ConstructorDescriptor) { - appendModality(descriptor) - } - } - return this - } +@Inject constructor( + val resolutionFacade: DokkaResolutionFacade, + val passConfiguration: DokkaConfiguration.PassConfiguration, + val logger: DokkaLogger +) { - fun DocumentationNode.appendModality(descriptor: MemberDescriptor) { - var modality = descriptor.modality - if (modality == Modality.OPEN) { - val containingClass = descriptor.containingDeclaration as? ClassDescriptor - if (containingClass?.modality == Modality.FINAL) { - modality = Modality.FINAL - } - } - val modifier = modality.name.toLowerCase() - appendTextNode(modifier, NodeKind.Modifier) - } - - fun DocumentationNode.appendInline(descriptor: DeclarationDescriptor, psi: KtModifierListOwner) { - if (!psi.hasModifier(KtTokens.INLINE_KEYWORD)) return - if (descriptor is FunctionDescriptor - && descriptor.valueParameters.none { it.hasFunctionOrSuspendFunctionType }) return - appendTextNode(KtTokens.INLINE_KEYWORD.value, NodeKind.Modifier) - } - - fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) { - val modifier = descriptor.visibility.normalize().displayName - appendTextNode(modifier, NodeKind.Modifier) - } - - fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) { + private fun DocumentationNodes.Class.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) { val unwrappedType = superType.unwrap() if (unwrappedType is AbbreviatedType) { appendSupertype(descriptor, unwrappedType.abbreviation, backref) } else { - appendType(unwrappedType, NodeKind.Supertype) - val superclass = unwrappedType.constructor.declarationDescriptor - if (backref) { - link(superclass, descriptor, RefKind.Inheritor) - } - link(descriptor, superclass, RefKind.Superclass) + appendType(unwrappedType, descriptor) } } - fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) { - if (projection.isStarProjection) { - appendTextNode("*", NodeKind.Type) - } else { - appendType(projection.type, kind, projection.projectionKind.label) - } - } - - fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: NodeKind = NodeKind.Type, prefix: String = "") { + private fun DocumentationNodes.Class.appendType( + kotlinType: KotlinType?, + descriptor: ClassDescriptor? + ) { if (kotlinType == null) return (kotlinType.unwrap() as? AbbreviatedType)?.let { - return appendType(it.abbreviation) + return appendType(it.abbreviation, descriptor) } if (kotlinType.isDynamic()) { - append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail) + append(kind.createNode("dynamic", descriptor), RefKind.Detail) return } @@ -198,244 +100,80 @@ class DocumentationBuilder is Named -> classifierDescriptor.name.asString() else -> "<anonymous>" } - val node = DocumentationNode(name, Content.Empty, kind) - if (prefix != "") { - node.appendTextNode(prefix, NodeKind.Modifier) - } - if (kotlinType.isNullabilityFlexible()) { - node.appendTextNode("!", NodeKind.NullabilityModifier) - } else if (kotlinType.isMarkedNullable) { - node.appendTextNode("?", NodeKind.NullabilityModifier) - } - if (classifierDescriptor != null) { - val externalLink = - linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor) - if (externalLink != null) { - if (classifierDescriptor !is TypeParameterDescriptor) { - val targetNode = - refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true) - node.append(targetNode, RefKind.ExternalType) - node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - } else { - link( - node, classifierDescriptor, - if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link - ) - } - if (classifierDescriptor !is TypeParameterDescriptor) { - node.append( - DocumentationNode( - classifierDescriptor.fqNameUnsafe.asString(), - Content.Empty, - NodeKind.QualifiedName - ), RefKind.Detail - ) - } - } - + val node = kind.createNode(name, descriptor) append(node, RefKind.Detail) - node.appendAnnotations(kotlinType) for (typeArgument in kotlinType.arguments) { - node.appendProjection(typeArgument) - } - } - - fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean = - DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses - - fun DocumentationNode.appendAnnotations(annotated: Annotated) { - annotated.annotations.forEach { - it.build()?.let { annotationNode -> - if (annotationNode.isSinceKotlin()) { - appendSinceKotlin(annotationNode) - } - else { - val refKind = when { - it.isDocumented() -> - when { - annotationNode.isDeprecation() -> RefKind.Deprecation - else -> RefKind.Annotation - } - it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation - else -> return@forEach - } - append(annotationNode, refKind) - } - - } - } - } - - fun DocumentationNode.appendExternalLink(externalLink: String) { - append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - - fun DocumentationNode.appendExternalLink(descriptor: DeclarationDescriptor) { - val target = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(descriptor) - if (target != null) { - appendExternalLink(target) - } - } - - fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) { - val kotlinVersion = annotation - .detail(NodeKind.Parameter) - .detail(NodeKind.Value) - .name.removeSurrounding("\"") - - sinceKotlin = kotlinVersion - } - - fun DocumentationNode.appendDefaultSinceKotlin() { - if (sinceKotlin == null) { - sinceKotlin = passConfiguration.sinceKotlin - } - } - - fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) { - val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return - KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { - it !in knownModifiers - }.sortedBy { - MODIFIERS_ORDER.indexOf(it) - }.forEach { - if (psi.hasModifier(it)) { - appendTextNode(it.value, NodeKind.Modifier) - } + node.appendProjection(typeArgument, null) } - appendInline(descriptor, psi) } - fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) { - for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) { - append(platformNodeRegistry[platform], RefKind.Platform) - } - } - - fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated" - - fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation - - fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) { - appendSourceLink(sourceElement.getPsi(), passConfiguration.sourceLinks) - } - - fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) { - appendTextNode(descriptor.signature(), NodeKind.Signature, RefKind.Detail) - } - - fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? { + fun DocumentationNode<*>.appendChild(descriptor: DeclarationDescriptor) { if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { val node = descriptor.build() append(node, kind) - return node } - 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(passConfiguration)) 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) { - val membersToDocument = descriptor.collectMembersToDocument() - for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) { - if (memberDescriptor is ClassDescriptor) { - existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes - } - else { - val existingMemberNode = refGraph.lookup(memberDescriptor.signature()) - if (existingMemberNode != null) { - existingMemberNode.updatePlatforms(memberDescriptor) - } - else { - existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier) + fun DocumentationNode.appendMember(descriptor: DeclarationDescriptor) { + if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { + val existingNode = members.firstOrNull { it.descriptor?.fqNameSafe == descriptor.fqNameSafe } + if (existingNode != null) { + if (descriptor is ClassDescriptor) { + val membersToDocument = descriptor.collectMembersToDocument() + for ((memberDescriptor, _, _) in membersToDocument) { + if (memberDescriptor is ClassDescriptor) { + existingNode.appendMember(memberDescriptor) // recurse into nested classes + } else { + if (members.any { it.descriptor?.fqNameSafe == memberDescriptor.fqNameSafe }) { + existingNode.appendClassMember(memberDescriptor) + } } } } + } else { + appendChild(descriptor, RefKind.Member) } } - else { - appendChild(descriptor, RefKind.Member) - } - } - - private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) { - for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) { - append(platformNodeRegistry[platform], RefKind.Platform) - } } - fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor, - inheritedLinkKind: RefKind = RefKind.InheritedMember, - extraModifier: String?) { - if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull() - if (baseDescriptor != null) { - link(this, baseDescriptor, inheritedLinkKind) - } - } else { + private fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor) { + if (descriptor !is CallableMemberDescriptor || descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original - val child = appendChild(descriptorToUse, RefKind.Member) - if (extraModifier != null) { - child?.appendTextNode("static", NodeKind.Modifier) - } + appendChild(descriptorToUse, RefKind.Member) } } - fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) { - descriptors.forEach { descriptor -> - val node = appendChild(descriptor, kind) - node?.addReferenceTo(this, RefKind.TopLevelPage) - } - } - - fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>, - packageContent: Map<String, Content>, - packageDocumentationBuilder: PackageDocumentationBuilder) { - val allFqNames = fragments.filter{ it.isDocumented(passConfiguration) }.map { it.fqName }.distinct() + fun DocumentationNodes.Module.appendFragments( + fragments: Collection<PackageFragmentDescriptor>, + packageDocumentationBuilder: PackageDocumentationBuilder + ) { + val allFqNames = fragments.filter { it.isDocumented(passConfiguration) }.map { it.fqName }.distinct() for (packageName in allFqNames) { if (packageName.isRoot && !passConfiguration.includeRootPackage) continue - val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() } + val declarations = fragments.filter { it.fqName == packageName } + .flatMap { it.getMemberScope().getContributedDescriptors() } if (passConfiguration.skipEmptyPackages && declarations.none { it.isDocumented(passConfiguration) }) continue logger.info(" package $packageName: ${declarations.count()} declarations") - val packageNode = findOrCreatePackageNode(this, packageName.asString(), packageContent, this@DocumentationBuilder.refGraph) - packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, - declarations, allFqNames) + val packageNode = findOrCreatePackageNode(this, packageName.asString()) + packageDocumentationBuilder.buildPackageDocumentation( + this@DocumentationBuilder, packageName, packageNode, + declarations, allFqNames + ) } + } + fun findOrCreatePackageNode( + module: DocumentationNodes.Module, + packageName: String + ): DocumentationNode<*> { + val node = module?.member(DocumentationNodes.Package::class) ?: DocumentationNodes.Package(packageName) + if (module != null && node !in module.members) { + module.append(node, RefKind.Member) + } + return node } fun propagateExtensionFunctionsToSubclasses( @@ -466,12 +204,6 @@ class DocumentationBuilder ).asSequence() } - - val documentingDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() } - val documentingClasses = documentingDescriptors.filterIsInstance<ClassDescriptor>() - - val classHierarchy = buildClassHierarchy(documentingClasses) - val allExtensionFunctions = allDescriptors .filterIsInstance<CallableMemberDescriptor>() @@ -479,9 +211,9 @@ class DocumentationBuilder val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name } fun isIgnoredReceiverType(type: KotlinType) = - type.isDynamic() || - type.isAnyOrNullableAny() || - (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() }) + type.isDynamic() || + type.isAnyOrNullableAny() || + (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() }) for (extensionFunction in allExtensionFunctions) { @@ -492,53 +224,9 @@ class DocumentationBuilder ?: emptyList() if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue - val subclasses = - classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) } - if (subclasses.isEmpty()) continue - subclasses.values.flatten().forEach { subclass -> - if (subclass.isExtensionApplicable(extensionFunction) && - possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) { - - val hasExternalLink = - linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink( - extensionFunction - ) != null - if (hasExternalLink) { - val containerDesc = - extensionFunction.containingDeclaration as? PackageFragmentDescriptor - if (containerDesc != null) { - val container = refGraph.lookup(containerDesc.signature()) - ?: containerDesc.buildExternal() - container.append(extensionFunction.buildExternal(), RefKind.Member) - } - } - - refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension) - } - } } } - private fun ClassDescriptor.isExtensionApplicable(extensionFunction: CallableMemberDescriptor): Boolean { - val receiverType = extensionFunction.fuzzyExtensionReceiverType()?.makeNotNullable() - val classType = defaultType.toFuzzyType(declaredTypeParameters) - return receiverType != null && classType.checkIsSubtypeOf(receiverType) != null - } - - private fun buildClassHierarchy(classes: List<ClassDescriptor>): Map<ClassDescriptor, List<ClassDescriptor>> { - val result = hashMapOf<ClassDescriptor, MutableList<ClassDescriptor>>() - classes.forEach { cls -> - TypeUtils.getAllSupertypes(cls.defaultType).forEach { supertype -> - val classDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor - if (classDescriptor != null) { - val subtypesList = result.getOrPut(classDescriptor) { arrayListOf() } - subtypesList.add(cls) - } - } - } - return result - } - private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean { if (this == other) return false if (this is PropertyDescriptor && other is PropertyDescriptor) { @@ -570,89 +258,47 @@ class DocumentationBuilder else -> throw IllegalStateException("Descriptor $this is not known") } - fun PackageFragmentDescriptor.buildExternal(): DocumentationNode { - val node = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.Package) - - val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(this) - if (externalLink != null) { - node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - register(this, node) - return node - } - - fun CallableDescriptor.buildExternal(): DocumentationNode = when(this) { - is FunctionDescriptor -> build(true) - is PropertyDescriptor -> build(true) - else -> throw IllegalStateException("Descriptor $this is not known") - } - - fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) { - is ClassDescriptor -> build(external) - is TypeAliasDescriptor -> build(external) + is ClassDescriptor -> build(this, external) + is TypeAliasDescriptor -> build() is TypeParameterDescriptor -> build() else -> throw IllegalStateException("Descriptor $this is not known") } - fun TypeAliasDescriptor.build(external: Boolean = false): DocumentationNode { - val node = nodeForDescriptor(this, NodeKind.TypeAlias) - - if (!external) { - node.appendDefaultSinceKotlin() - node.appendAnnotations(this) - } - node.appendModifiers(this) - node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail) - - node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType) - - if (!external) { - node.appendSourceLink(source) - node.appendDefaultPlatforms(this) - } - register(this, node) + fun TypeAliasDescriptor.build(): DocumentationNode { + val node = DocumentationNodes.TypeAlias(name.asString(), this) + node.appendType(underlyingType, this, DocumentationNodes.TypeAliasUnderlyingType::class) return node } - fun ClassDescriptor.build(external: Boolean = false): DocumentationNode { - val kind = when { - kind == ClassKind.OBJECT -> NodeKind.Object - kind == ClassKind.INTERFACE -> NodeKind.Interface - kind == ClassKind.ENUM_CLASS -> NodeKind.Enum - kind == ClassKind.ANNOTATION_CLASS -> NodeKind.AnnotationClass - kind == ClassKind.ENUM_ENTRY -> NodeKind.EnumItem - isSubclassOfThrowable() -> NodeKind.Exception - else -> NodeKind.Class + fun ClassDescriptor.build(descriptor: DeclarationDescriptor, external: Boolean = false): DocumentationNode { + val node = when { + kind == ClassKind.OBJECT -> DocumentationNodes.Object(descriptor.name.asString(), descriptor) + kind == ClassKind.INTERFACE -> DocumentationNodes.Interface(descriptor.name.asString(), descriptor) + kind == ClassKind.ENUM_CLASS -> DocumentationNodes.Enum(descriptor.name.asString(), descriptor) + kind == ClassKind.ANNOTATION_CLASS -> DocumentationNodes.AnnotationClass(descriptor.name.asString(), descriptor) + kind == ClassKind.ENUM_ENTRY -> DocumentationNodes.EnumItem(descriptor.name.asString(), descriptor) + isSubclassOfThrowable() -> DocumentationNodes.Exception(descriptor.name.asString(), descriptor) + else -> DocumentationNodes.Class(descriptor.name.asString(), descriptor) } - val node = nodeForDescriptor(this, kind, external) - register(this, node) supertypesWithAnyPrecise().forEach { node.appendSupertype(this, it, !external) } - if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) { - node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail) - } if (!external) { - for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) { - node.appendClassMember(descriptor, inheritedLinkKind, extraModifier) + for ((membersDescriptor, _, _) in collectMembersToDocument()) { + node.appendClassMember(membersDescriptor) } - node.appendDefaultSinceKotlin() - node.appendAnnotations(this) - } - node.appendModifiers(this) - if (!external) { - node.appendSourceLink(source) - node.appendDefaultPlatforms(this) } return node } - data class ClassMember(val descriptor: DeclarationDescriptor, - val inheritedLinkKind: RefKind = RefKind.InheritedMember, - val extraModifier: String? = null) + data class ClassMember( + val descriptor: DeclarationDescriptor, + val inheritedLinkKind: RefKind = RefKind.InheritedMember, + val extraModifier: String? = null + ) - fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> { + private fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> { val result = arrayListOf<ClassMember>() if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) { val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS) @@ -663,11 +309,11 @@ class DocumentationBuilder } defaultType.memberScope.getContributedDescriptors() - .filter { it != companionObjectDescriptor } - .mapTo(result) { ClassMember(it) } + .filter { it != companionObjectDescriptor } + .mapTo(result) { ClassMember(it) } staticScope.getContributedDescriptors() - .mapTo(result) { ClassMember(it, extraModifier = "static") } + .mapTo(result) { ClassMember(it, extraModifier = "static") } val companionObjectDescriptor = companionObjectDescriptor if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(passConfiguration)) { @@ -678,274 +324,51 @@ class DocumentationBuilder } if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty() - || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) { + || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) { result += ClassMember(companionObjectDescriptor) } } return result } - fun CallableDescriptor.isInheritedFromAny(): Boolean { + private fun CallableDescriptor.isInheritedFromAny(): Boolean { return findTopMostOverriddenDescriptors().any { DescriptorUtils.getFqNameSafe(it.containingDeclaration).asString() == "kotlin.Any" } } - fun ClassDescriptor.isSubclassOfThrowable(): Boolean = - defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable } + private fun ClassDescriptor.isSubclassOfThrowable(): Boolean = + defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable } - fun ConstructorDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, NodeKind.Constructor) - node.appendInPageChildren(valueParameters, RefKind.Detail) - node.appendDefaultPlatforms(this) - node.appendDefaultSinceKotlin() - register(this, node) - return node - } + fun ConstructorDescriptor.build(): DocumentationNode = + DocumentationNodes.Constructor(name.asString(), this) private fun CallableMemberDescriptor.inCompanionObject(): Boolean { val containingDeclaration = containingDeclaration - if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject ?: false) { + if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject == true) { return true } val receiver = extensionReceiverParameter return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false } - fun FunctionDescriptor.build(external: Boolean = false): DocumentationNode { - if (ErrorUtils.containsErrorType(this)) { - logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}") - } - - val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function, external) - - node.appendInPageChildren(typeParameters, RefKind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) } - node.appendInPageChildren(valueParameters, RefKind.Detail) - node.appendType(returnType) - if (!external) { - node.appendDefaultSinceKotlin() - } - node.appendAnnotations(this) - node.appendModifiers(this) - if (!external) { - node.appendSourceLink(source) - node.appendDefaultPlatforms(this) - } else { - node.appendExternalLink(this) - } - - overriddenDescriptors.forEach { - addOverrideLink(it, this) - } - - register(this, node) - return node - } - - fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) { - val source = baseClassFunction.original.source.getPsi() - if (source != null) { - link(overridingFunction, baseClassFunction, RefKind.Override) - } else { - baseClassFunction.overriddenDescriptors.forEach { - addOverrideLink(it, overridingFunction) - } - } - } - - fun PropertyDescriptor.build(external: Boolean = false): DocumentationNode { - val node = nodeForDescriptor( - this, - if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property, - external - ) - node.appendInPageChildren(typeParameters, RefKind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) } - node.appendType(returnType) - if (!external) { - node.appendDefaultSinceKotlin() - } - node.appendAnnotations(this) - node.appendModifiers(this) - if (!external) { - node.appendSourceLink(source) - if (isVar) { - node.appendTextNode("var", NodeKind.Modifier) - } - - if (isConst) { - this.compileTimeInitializer?.toDocumentationNode()?.let { node.append(it, RefKind.Detail) } - } - - - getter?.let { - if (!it.isDefault) { - node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter") - } - } - setter?.let { - if (!it.isDefault) { - node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter") - } - } - node.appendDefaultPlatforms(this) - } - if (external) { - node.appendExternalLink(this) - } - - overriddenDescriptors.forEach { - addOverrideLink(it, this) - } - - register(this, node) - return node - } - - fun DocumentationNode.addAccessorDocumentation(documentation: Content, prefix: String) { - if (documentation == Content.Empty) return - updateContent { - if (!documentation.children.isEmpty()) { - val section = addSection(prefix, null) - documentation.children.forEach { section.append(it) } - } - documentation.sections.forEach { - val section = addSection("$prefix ${it.tag}", it.subjectName) - it.children.forEach { section.append(it) } - } - } - } - - fun ValueParameterDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, NodeKind.Parameter) - node.appendType(varargElementType ?: type) - if (declaresDefaultValue()) { - val psi = source.getPsi() as? KtParameter - if (psi != null) { - val defaultValueText = psi.defaultValue?.text - if (defaultValueText != null) { - node.appendTextNode(defaultValueText, NodeKind.Value) - } - } - } - node.appendDefaultSinceKotlin() - node.appendAnnotations(this) - node.appendModifiers(this) - if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) { - node.appendTextNode("vararg", NodeKind.Modifier) - } - register(this, node) - return node - } - - fun TypeParameterDescriptor.build(): DocumentationNode { - val doc = descriptorDocumentationParser.parseDocumentation(this) - val name = name.asString() - val prefix = variance.label - - val node = DocumentationNode(name, doc, NodeKind.TypeParameter) - if (prefix != "") { - node.appendTextNode(prefix, NodeKind.Modifier) - } - if (isReified) { - node.appendTextNode("reified", NodeKind.Modifier) - } - - for (constraint in upperBounds) { - if (KotlinBuiltIns.isDefaultBound(constraint)) { - continue - } - node.appendType(constraint, NodeKind.UpperBound) - } - register(this, node) - return node - } + fun FunctionDescriptor.build(): DocumentationNode = + if (inCompanionObject()) + DocumentationNodes.CompanionObjectFunction(name.asString(),this) + else + DocumentationNodes.Function(name.asString(),this) - fun ReceiverParameterDescriptor.build(): DocumentationNode { - var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!! - if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) { - receiverClass = receiverClass.containingDeclaration!! - } else if (receiverClass is TypeParameterDescriptor) { - val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor - if (upperBoundClass != null) { - receiverClass = upperBoundClass - } - } + fun PropertyDescriptor.build(): DocumentationNode = + DocumentationNodes.Property(name.asString(), this) - if ((containingDeclaration as? FunctionDescriptor)?.dispatchReceiverParameter == null) { - link(receiverClass, containingDeclaration, RefKind.Extension) - } - - val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver) - node.appendType(type) - register(this, node) - return node - } - - fun AnnotationDescriptor.build(): DocumentationNode? { - val annotationClass = type.constructor.declarationDescriptor - if (annotationClass == null || ErrorUtils.isError(annotationClass)) { - return null - } - val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, NodeKind.Annotation) - allValueArguments.forEach { (name, value) -> - val valueNode = value.toDocumentationNode() - if (valueNode != null) { - val paramNode = DocumentationNode(name.asString(), Content.Empty, NodeKind.Parameter) - paramNode.append(valueNode, RefKind.Detail) - node.append(paramNode, RefKind.Detail) - } - } - return node - } - - fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value.let { value -> - val text = when (value) { - is String -> - "\"" + StringUtil.escapeStringCharacters(value) + "\"" - is EnumEntrySyntheticClassDescriptor -> - value.containingDeclaration.name.asString() + "." + value.name.asString() - is Pair<*, *> -> { - val (classId, name) = value - if (classId is ClassId && name is Name) { - classId.shortClassName.asString() + "." + name.asString() - } else { - value.toString() - } - } - else -> "$value" - } - DocumentationNode(text, Content.Empty, NodeKind.Value) - } + fun ValueParameterDescriptor.build(): DocumentationNode = + DocumentationNodes.Parameter(name.asString(), this) + fun TypeParameterDescriptor.build(): DocumentationNode = + DocumentationNodes.TypeParameter(name.asString(), this) - fun DocumentationNode.getParentForPackageMember( - descriptor: DeclarationDescriptor, - externalClassNodes: MutableMap<FqName, DocumentationNode>, - allFqNames: Collection<FqName>, - packageName: FqName - ): DocumentationNode { - if (descriptor is CallableMemberDescriptor) { - val extensionClassDescriptor = descriptor.getExtensionClassDescriptor() - if (extensionClassDescriptor != null && isExtensionForExternalClass(descriptor, extensionClassDescriptor, allFqNames) && - !ErrorUtils.isError(extensionClassDescriptor)) { - val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor) - return externalClassNodes.getOrPut(fqName) { - val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass) - val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(extensionClassDescriptor) - if (externalLink != null) { - newNode.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - append(newNode, RefKind.Member) - refGraph.register("${packageName.asString()}:${extensionClassDescriptor.signature()}", newNode) - newNode - } - } - } - return this - } - + fun ReceiverParameterDescriptor.build(): DocumentationNode = + DocumentationNodes.Receiver(name.asString(), this) } fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean { @@ -956,25 +379,22 @@ fun DeclarationDescriptor.isDocumented(passConfiguration: DokkaConfiguration.Pas && (!passConfiguration.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated()) } -private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION +private fun DeclarationDescriptor.isGenerated() = + this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder { - override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>, - allFqNames: Collection<FqName>) { - val externalClassNodes = hashMapOf<FqName, DocumentationNode>() + + override fun buildPackageDocumentation( + documentationBuilder: DocumentationBuilder, + packageName: FqName, + packageNode: DocumentationNode, + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName> + ) { declarations.forEach { descriptor -> with(documentationBuilder) { if (descriptor.isDocumented(passConfiguration)) { - val parent = packageNode.getParentForPackageMember( - descriptor, - externalClassNodes, - allFqNames, - packageName - ) - parent.appendOrUpdateMember(descriptor) + packageNode.appendMember(descriptor) } } } @@ -982,17 +402,19 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder { } class KotlinJavaDocumentationBuilder -@Inject constructor(val resolutionFacade: DokkaResolutionFacade, - val documentationBuilder: DocumentationBuilder, - val passConfiguration: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger) : JavaDocumentationBuilder { +@Inject constructor( + val resolutionFacade: DokkaResolutionFacade, + val documentationBuilder: DocumentationBuilder, + val passConfiguration: DokkaConfiguration.PassConfiguration, + val logger: DokkaLogger +) : JavaDocumentationBuilder { override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) { val classDescriptors = file.classes.map { it.getJavaClassDescriptor(resolutionFacade) } if (classDescriptors.any { it != null && it.isDocumented(passConfiguration) }) { - val packageNode = findOrCreatePackageNode(module, file.packageName, packageContent, documentationBuilder.refGraph) + val packageNode = documentationBuilder.findOrCreatePackageNode(module, file.packageName) for (descriptor in classDescriptors.filterNotNull()) { with(documentationBuilder) { @@ -1003,24 +425,6 @@ class KotlinJavaDocumentationBuilder } } -private val hiddenAnnotations = setOf( - KotlinBuiltIns.FQ_NAMES.parameterName.asString() -) - -private fun AnnotationDescriptor.isHiddenInDocumentation() = - type.constructor.declarationDescriptor?.fqNameSafe?.asString() in hiddenAnnotations - -private fun AnnotationDescriptor.isDocumented(): Boolean { - if (source.getPsi() != null && mustBeDocumented()) return true - val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString() - return annotationClassName == KotlinBuiltIns.FQ_NAMES.extensionFunctionType.asString() -} - -fun AnnotationDescriptor.mustBeDocumented(): Boolean { - val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false - return annotationClass.isDocumentedAnnotation() -} - fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConfiguration.PassConfiguration): Boolean { if (passConfiguration.effectivePackageOptions(fqNameSafe).suppress) return true @@ -1037,25 +441,12 @@ fun DeclarationDescriptor.isDocumentationSuppressed(passConfiguration: DokkaConf } fun DeclarationDescriptor.sourcePsi() = - ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi + ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any { DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated" } || (this is ConstructorDescriptor && containingDeclaration.isDeprecated()) -fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? { - val extensionReceiver = extensionReceiverParameter - if (extensionReceiver != null) { - val type = extensionReceiver.type - val receiverClass = type.constructor.declarationDescriptor as? ClassDescriptor - if (receiverClass?.isCompanionObject ?: false) { - return receiverClass?.containingDeclaration as? ClassifierDescriptor - } - return receiverClass - } - return null -} - fun DeclarationDescriptor.signature(): String { if (this != original) return original.signature() return when (this) { @@ -1126,28 +517,6 @@ fun DeclarationDescriptor.sourceLocation(): String? { return null } -fun DocumentationModule.prepareForGeneration(configuration: DokkaConfiguration) { - if (configuration.generateIndexPages) { - generateAllTypesNode() - } - nodeRefGraph.resolveReferences() -} - -fun DocumentationNode.generateAllTypesNode() { - val allTypes = members(NodeKind.Package) - .flatMap { it.members.filter { - it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass - || (it.kind == NodeKind.GroupNode && it.origins.all { it.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) - for (typeNode in allTypes) { - allTypesNode.addReferenceTo(typeNode, RefKind.Member) - } - - append(allTypesNode, RefKind.Member) -} - fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> { if (KotlinBuiltIns.isAny(this)) { return emptyList() @@ -1160,5 +529,6 @@ fun PassConfiguration.effectivePackageOptions(pack: String): DokkaConfiguration. return perPackageOptions.firstOrNull { pack == it.prefix || pack.startsWith(it.prefix + ".") } ?: rootPackageOptions } -fun PassConfiguration.effectivePackageOptions(pack: FqName): DokkaConfiguration.PackageOptions = effectivePackageOptions(pack.asString()) +fun PassConfiguration.effectivePackageOptions(pack: FqName): DokkaConfiguration.PackageOptions = + effectivePackageOptions(pack.asString()) diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt index ee9d8c51..70c04da6 100644 --- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt @@ -30,8 +30,7 @@ class KotlinAsJavaDocumentationBuilder return } - val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.passConfiguration, - documentationBuilder.refGraph, + val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder, kotlinAsJavaDocumentationParser) psiPackage.classes.filter { it is KtLightElement<*, *> }.filter { it.isVisibleInDocumentation() }.forEach { diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt index 66ee33e1..19ba22a6 100644 --- a/core/src/main/kotlin/Model/DocumentationNode.kt +++ b/core/src/main/kotlin/Model/DocumentationNode.kt @@ -1,330 +1,75 @@ package org.jetbrains.dokka -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import java.util.* -import kotlin.reflect.KClass -import kotlin.reflect.full.primaryConstructor +import org.jetbrains.dokka.links.ClassReference +import org.jetbrains.kotlin.descriptors.* class DocumentationNodes { - class Unknown(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) + class Module(name: String, parent: DocumentationNode<*>? = null): + DocumentationNode<Nothing>(name, parent = parent) - class Package(name: String) : - DocumentationNode(name) + class Package(name: String, parent: DocumentationNode<*>): + DocumentationNode<Nothing>(name, parent = parent) - class Class(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { + class Class(name: String, descriptor: ClassDescriptor, parent: DocumentationNode<*>? = null) : + DocumentationNode<ClassDescriptor>(name, descriptor, parent) { override val classLike: Boolean = true - } - - class Interface(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val classLike: Boolean = true - override val superclassType: DocumentationNode? = null - } - - class Enum(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val classLike: Boolean = true - } - - class AnnotationClass(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val classLike: Boolean = true - } - - class Exception(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val classLike: Boolean = true - } - - class EnumItem(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val memberLike = true - } - - class Object(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val classLike: Boolean = true - } - - class TypeAlias(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Constructor(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { + val supertypes = mutableListOf<ClassReference>() + val isInterface: Boolean + get() = descriptor?.kind == ClassKind.CLASS + val isEnum: Boolean + get() = descriptor?.kind == ClassKind.ENUM_CLASS + val isEnumEntry: Boolean + get() = descriptor?.kind == ClassKind.ENUM_ENTRY + val isAnnotationClass: Boolean + get() = descriptor?.kind == ClassKind.ANNOTATION_CLASS + val isObject: Boolean + get() = descriptor?.kind == ClassKind.OBJECT + } + + class Constructor(name: String, descriptor: ConstructorDescriptor) : + DocumentationNode<ConstructorDescriptor>(name, descriptor) { override val memberLike = true } - class Function(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { + class Function(name: String, descriptor: FunctionDescriptor) : + DocumentationNode<FunctionDescriptor>(name, descriptor) { override val memberLike = true } - class Property(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { + class Property(name: String, descriptor: PropertyDescriptor) : + DocumentationNode<PropertyDescriptor>(name, descriptor) { override val memberLike = true } - - class Field(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { +/* + class Field(name: String, descriptor: FieldDescriptor) : + DocumentationNode<FieldDescriptor>(name, descriptor) { override val memberLike = true - } - - class CompanionObjectProperty(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val memberLike = true - } - - class CompanionObjectFunction(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val memberLike = true - } - - class Parameter(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Receiver(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class TypeParameter(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Type(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Supertype(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) { - override val superclassType: DocumentationNode? = - (links + listOfNotNull(externalType)).firstOrNull { it.classLike }?.superclassType - } - - class UpperBound(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class LowerBound(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class TypeAliasUnderlyingType(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class NullabilityModifier(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Module(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class ExternalClass(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Annotation(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class Value(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class SourceUrl(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class SourcePosition(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class ExternalLink(name: String) : DocumentationNode(name) - - class QualifiedName(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) + }*/ - class Platform(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class AllTypes(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) - - class OverloadGroupNote(name: String, descriptor: DeclarationDescriptor?) : - DocumentationNode(name, descriptor) + class Parameter(name: String, descriptor: ParameterDescriptor?) : + DocumentationNode<ParameterDescriptor>(name, descriptor) +/* + class Annotation(name: String, descriptor: AnnotationDescriptor?) : + DocumentationNode<AnnotationDescriptor>(name, descriptor)*/ } -abstract class DocumentationNode( +abstract class DocumentationNode<T: DeclarationDescriptor>( var name: String, - val descriptor: DeclarationDescriptor? = null + val descriptor: T? = null, + val parent: DocumentationNode<*>? = null ) { - private val references = LinkedHashSet<DocumentationReference>() + private val children = mutableListOf<DocumentationNode<*>>() open val classLike = false open val memberLike = false - val owner: DocumentationNode? - get() = references(RefKind.Owner).singleOrNull()?.to - val details: List<DocumentationNode> - get() = references(RefKind.Detail).map { it.to } - val members: List<DocumentationNode> - get() = references(RefKind.Member).map { it.to } - val origins: List<DocumentationNode> - get() = references(RefKind.Origin).map { it.to } - - val inheritedMembers: List<DocumentationNode> - get() = references(RefKind.InheritedMember).map { it.to } - val allInheritedMembers: List<DocumentationNode> - get() = recursiveInheritedMembers() - val inheritedCompanionObjectMembers: List<DocumentationNode> - get() = references(RefKind.InheritedCompanionObjectMember).map { it.to } - val extensions: List<DocumentationNode> - get() = references(RefKind.Extension).map { it.to } - val inheritors: List<DocumentationNode> - get() = references(RefKind.Inheritor).map { it.to } - val overrides: List<DocumentationNode> - get() = references(RefKind.Override).map { it.to } - val links: List<DocumentationNode> - get() = references(RefKind.Link).map { it.to } - val hiddenLinks: List<DocumentationNode> - get() = references(RefKind.HiddenLink).map { it.to } - val annotations: List<DocumentationNode> - get() = references(RefKind.Annotation).map { it.to } - val deprecation: DocumentationNode? - get() = references(RefKind.Deprecation).singleOrNull()?.to - val platforms: List<String> - get() = references(RefKind.Platform).map { it.to.name } - val externalType: DocumentationNode? - get() = references(RefKind.ExternalType).map { it.to }.firstOrNull() - - open val superclassType: DocumentationNode? - get() = if (classLike) { - supertypes.firstOrNull { - (it.links + listOfNotNull(it.externalType)).any { it.isSuperclassFor(this) } - } - } else null - - val superclassTypeSequence: Sequence<DocumentationNode> - get() = generateSequence(superclassType) { - it.superclassType - } - - // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice - fun addReferenceTo(to: DocumentationNode, kind: RefKind) { - references.add(DocumentationReference(this, to, kind)) - } - - fun addReference(reference: DocumentationReference) { - references.add(reference) - } - - fun dropReferences(predicate: (DocumentationReference) -> Boolean) { - references.removeAll(predicate) - } - - fun addAllReferencesFrom(other: DocumentationNode) { - references.addAll(other.references) - } - - private fun Collection<DocumentationNode>.filterByKind(kind: KClass<out DocumentationNode>) = - filter { node: DocumentationNode -> node::class == kind } - - private fun Collection<DocumentationNode>.singleByKind(kind: KClass<out DocumentationNode>) = - single { node: DocumentationNode -> node::class == kind } - - fun details(kind: KClass<out DocumentationNode>) = details.filterByKind(kind) - fun members(kind: KClass<out DocumentationNode>) = members.filterByKind(kind) - fun inheritedMembers(kind: KClass<out DocumentationNode>): List<DocumentationNode> = - inheritedMembers.filterByKind(kind) - - fun inheritedCompanionObjectMembers(kind: KClass<out DocumentationNode>): List<DocumentationNode> = - inheritedCompanionObjectMembers.filterByKind(kind) - - fun links(kind: KClass<out DocumentationNode>): List<DocumentationNode> = links.filterByKind(kind) - - fun detail(kind: KClass<out DocumentationNode>): DocumentationNode = details.singleByKind(kind) - fun detailOrNull(kind: KClass<out DocumentationNode>): DocumentationNode? = - details.singleOrNull { it::class == kind } - - fun member(kind: KClass<out DocumentationNode>): DocumentationNode = members.singleByKind(kind) - fun link(kind: KClass<out DocumentationNode>): DocumentationNode = links.singleByKind(kind) - - - fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind } - fun allReferences(): Set<DocumentationReference> = references + fun addChild(child: DocumentationNode<*>) = + children.add(child) override fun toString(): String { return "${javaClass.name}:$name" } -} - -fun KClass<out DocumentationNode>.createNode(name: String, descriptor: DeclarationDescriptor? = null) = - primaryConstructor?.call(name, descriptor) - ?: throw IllegalArgumentException("Cannot create node of type ${this::class}: invalid primary constructor") - -val DocumentationNode.supertypes: List<DocumentationNode> - get() = details(DocumentationNodes.Supertype::class) - -class DocumentationModule(name: String) : DocumentationNode(name) - -val DocumentationNode.path: List<DocumentationNode> - get() { - val parent = owner ?: return listOf(this) - return parent.path + this - } - -fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) { - addReferenceTo(child, kind) - when (kind) { - RefKind.Detail -> child.addReferenceTo(this, RefKind.Owner) - RefKind.Member -> child.addReferenceTo(this, RefKind.Owner) - RefKind.Owner -> child.addReferenceTo(this, RefKind.Member) - RefKind.Origin -> child.addReferenceTo(this, RefKind.Owner) - else -> { /* Do not add any links back for other types */ - } - } -} - -fun DocumentationNode.appendTextNode( - text: String, - kind: KClass<out DocumentationNode>, - descriptor: DeclarationDescriptor? = null, - refKind: RefKind = RefKind.Detail -) { - append(kind.createNode(text, descriptor), refKind) -} - -fun DocumentationNode.qualifiedName(): String { - if (this is DocumentationNodes.Type) { - return qualifiedNameFromType() - } else if (this is DocumentationNodes.Package) { - return name - } - return path.dropWhile { it is DocumentationNodes.Module }.map { it.name }.filter { it.isNotEmpty() } - .joinToString(".") -} - -fun DocumentationNode.simpleName() = name.substringAfterLast('.') - -private fun DocumentationNode.recursiveInheritedMembers(): List<DocumentationNode> { - val allInheritedMembers = mutableListOf<DocumentationNode>() - recursiveInheritedMembers(allInheritedMembers) - return allInheritedMembers -} - -private fun DocumentationNode.recursiveInheritedMembers(allInheritedMembers: MutableList<DocumentationNode>) { - allInheritedMembers.addAll(inheritedMembers) - System.out.println(allInheritedMembers.size) - inheritedMembers.groupBy { it.owner!! }.forEach { (node, _) -> - node.recursiveInheritedMembers(allInheritedMembers) - } -} - -private fun DocumentationNode.isSuperclassFor(node: DocumentationNode): Boolean { - return when (node) { - is DocumentationNodes.Object, - is DocumentationNodes.Class, - is DocumentationNodes.Enum -> this is DocumentationNodes.Class - is DocumentationNodes.Exception -> this is DocumentationNodes.Class || this is DocumentationNodes.Exception - else -> false - } -} - -fun DocumentationNode.classNodeNameWithOuterClass(): String { - assert(classLike) - return path.dropWhile { it is DocumentationNodes.Package || it is DocumentationNodes.Module } - .joinToString(separator = ".") { it.name } }
\ No newline at end of file diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt deleted file mode 100644 index e46a4a21..00000000 --- a/core/src/main/kotlin/Model/DocumentationReference.kt +++ /dev/null @@ -1,115 +0,0 @@ -package org.jetbrains.dokka - -import com.google.inject.Singleton - -enum class RefKind { - Owner, - Member, - InheritedMember, - InheritedCompanionObjectMember, - Detail, - Link, - HiddenLink, - Extension, - Inheritor, - Superclass, - Override, - Annotation, - HiddenAnnotation, - Deprecation, - TopLevelPage, - Platform, - ExternalType, - Origin, - SinceKotlin -} - -data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) { -} - -sealed class NodeResolver { - abstract fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode? - class BySignature(var signature: String) : NodeResolver() { - override fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode? { - return nodeRephGraph.lookup(signature) - } - } - - class Exact(var exactNode: DocumentationNode) : NodeResolver() { - override fun resolve(nodeRephGraph: NodeReferenceGraph): DocumentationNode? { - return exactNode - } - } -} - -class PendingDocumentationReference(val lazyNodeFrom: NodeResolver, - val lazyNodeTo: NodeResolver, - val kind: RefKind) { - fun resolve(nodeRephGraph: NodeReferenceGraph) { - val fromNode = lazyNodeFrom.resolve(nodeRephGraph) - val toNode = lazyNodeTo.resolve(nodeRephGraph) - if (fromNode != null && toNode != null) { - fromNode.addReferenceTo(toNode, kind) - } - } -} - -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) { - nodeMap[signature] = node - } - - fun link(fromNode: DocumentationNode, toSignature: String, kind: RefKind) { - references.add( - PendingDocumentationReference( - NodeResolver.Exact(fromNode), - NodeResolver.BySignature(toSignature), - kind - )) - } - - fun link(fromSignature: String, toNode: DocumentationNode, kind: RefKind) { - references.add( - PendingDocumentationReference( - NodeResolver.BySignature(fromSignature), - NodeResolver.Exact(toNode), - kind - ) - ) - } - - fun link(fromSignature: String, toSignature: String, kind: RefKind) { - references.add( - PendingDocumentationReference( - NodeResolver.BySignature(fromSignature), - NodeResolver.BySignature(toSignature), - kind - ) - ) - } - - fun addReference(reference: PendingDocumentationReference) { - references.add(reference) - } - - fun lookup(signature: String) = nodeMap[signature] - - fun lookupOrWarn(signature: String, logger: DokkaLogger): DocumentationNode? { - val result = nodeMap[signature] - if (result == null) { - logger.warn("Can't find node by signature `$signature`." + - "This is probably caused by invalid configuration of cross-module dependencies") - } - return result - } - - fun resolveReferences() { - references.forEach { it.resolve(this) } - } -}
\ No newline at end of file diff --git a/core/src/main/kotlin/Utilities/DokkaModules.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt index 919ec30f..94fc5c62 100644 --- a/core/src/main/kotlin/Utilities/DokkaModules.kt +++ b/core/src/main/kotlin/Utilities/DokkaModules.kt @@ -26,7 +26,6 @@ class DokkaRunModule(val configuration: DokkaConfiguration) : Module { class DokkaAnalysisModule(val environment: AnalysisEnvironment, val configuration: DokkaConfiguration, val defaultPlatformsProvider: DefaultPlatformsProvider, - val nodeReferenceGraph: NodeReferenceGraph, val passConfiguration: DokkaConfiguration.PassConfiguration, val logger: DokkaLogger) : Module { override fun configure(binder: Binder) { @@ -43,8 +42,6 @@ class DokkaAnalysisModule(val environment: AnalysisEnvironment, binder.bind<DefaultPlatformsProvider>().toInstance(defaultPlatformsProvider) - binder.bind<NodeReferenceGraph>().toInstance(nodeReferenceGraph) - val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", configuration.format) descriptor.configureAnalysis(binder) } diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt index 64989701..35eb6497 100644 --- a/core/src/main/kotlin/links/DRI.kt +++ b/core/src/main/kotlin/links/DRI.kt @@ -66,5 +66,7 @@ data class Callable(val name: String, val receiver: String, val returnType: Stri } } +data class ClassReference(val dri: DRI, val subs: MutableList<ClassReference> = mutableListOf()) + private operator fun <T> List<T>.component6(): T = get(5) |