diff options
Diffstat (limited to 'core/src/main/kotlin')
36 files changed, 1005 insertions, 825 deletions
diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt index a5e35a0e..b0c39ee5 100644 --- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt +++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt @@ -57,7 +57,7 @@ import java.io.File * $messageCollector: required by compiler infrastructure and will receive all compiler messages * $body: optional and can be used to configure environment without creating local variable */ -public class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable { +class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable { val configuration = CompilerConfiguration(); init { @@ -119,14 +119,14 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector) : Dispo /** * Classpath for this environment. */ - public val classpath: List<File> + val classpath: List<File> get() = configuration.jvmClasspathRoots /** * Adds list of paths to classpath. * $paths: collection of files to add */ - public fun addClasspath(paths: List<File>) { + fun addClasspath(paths: List<File>) { configuration.addJvmClasspathRoots(paths) } @@ -134,14 +134,14 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector) : Dispo * Adds path to classpath. * $path: path to add */ - public fun addClasspath(path: File) { + fun addClasspath(path: File) { configuration.addJvmClasspathRoot(path) } /** * List of source roots for this environment. */ - public val sources: List<String> + val sources: List<String> get() = configuration.get(CommonConfigurationKeys.CONTENT_ROOTS) ?.filterIsInstance<KotlinSourceRoot>() ?.map { it.path } ?: emptyList() @@ -150,25 +150,25 @@ public class AnalysisEnvironment(val messageCollector: MessageCollector) : Dispo * Adds list of paths to source roots. * $list: collection of files to add */ - public fun addSources(list: List<String>) { + fun addSources(list: List<String>) { list.forEach { configuration.add(CommonConfigurationKeys.CONTENT_ROOTS, contentRootFromPath(it)) } } - public fun addRoots(list: List<ContentRoot>) { + fun addRoots(list: List<ContentRoot>) { configuration.addAll(CommonConfigurationKeys.CONTENT_ROOTS, list) } /** * Disposes the environment and frees all associated resources. */ - public override fun dispose() { + override fun dispose() { Disposer.dispose(this) } } -public fun contentRootFromPath(path: String): ContentRoot { +fun contentRootFromPath(path: String): ContentRoot { val file = File(path) return if (file.extension == "java") JavaSourceRoot(file, null) else KotlinSourceRoot(path) } diff --git a/core/src/main/kotlin/Formats/FormatDescriptor.kt b/core/src/main/kotlin/Formats/FormatDescriptor.kt index 0c7ca794..e384f223 100644 --- a/core/src/main/kotlin/Formats/FormatDescriptor.kt +++ b/core/src/main/kotlin/Formats/FormatDescriptor.kt @@ -3,7 +3,7 @@ package org.jetbrains.dokka.Formats import org.jetbrains.dokka.* import kotlin.reflect.KClass -public interface FormatDescriptor { +interface FormatDescriptor { val formatServiceClass: KClass<out FormatService>? val outlineServiceClass: KClass<out OutlineFormatService>? val generatorServiceClass: KClass<out Generator> diff --git a/core/src/main/kotlin/Formats/FormatService.kt b/core/src/main/kotlin/Formats/FormatService.kt index 73e54956..aa4e925c 100644 --- a/core/src/main/kotlin/Formats/FormatService.kt +++ b/core/src/main/kotlin/Formats/FormatService.kt @@ -7,7 +7,7 @@ package org.jetbrains.dokka * * [HtmlFormatService] – outputs documentation to HTML format * * [MarkdownFormatService] – outputs documentation in Markdown format */ -public interface FormatService { +interface FormatService { /** Returns extension for output files */ val extension: String diff --git a/core/src/main/kotlin/Formats/HtmlFormatService.kt b/core/src/main/kotlin/Formats/HtmlFormatService.kt index d513e41f..f78439ba 100644 --- a/core/src/main/kotlin/Formats/HtmlFormatService.kt +++ b/core/src/main/kotlin/Formats/HtmlFormatService.kt @@ -6,11 +6,11 @@ import java.io.File import java.nio.file.Path import java.nio.file.Paths -public open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService, - signatureGenerator: LanguageService, - val templateService: HtmlTemplateService) +open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService, + signatureGenerator: LanguageService, + val templateService: HtmlTemplateService) : StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService { - override public fun formatText(text: String): String { + override fun formatText(text: String): String { return text.htmlEscape() } diff --git a/core/src/main/kotlin/Formats/HtmlTemplateService.kt b/core/src/main/kotlin/Formats/HtmlTemplateService.kt index ae42a31b..13587b05 100644 --- a/core/src/main/kotlin/Formats/HtmlTemplateService.kt +++ b/core/src/main/kotlin/Formats/HtmlTemplateService.kt @@ -2,12 +2,12 @@ package org.jetbrains.dokka import java.nio.file.Path -public interface HtmlTemplateService { +interface HtmlTemplateService { fun appendHeader(to: StringBuilder, title: String?, basePath: Path) fun appendFooter(to: StringBuilder) companion object { - public fun default(css: String? = null): HtmlTemplateService { + fun default(css: String? = null): HtmlTemplateService { return object : HtmlTemplateService { override fun appendFooter(to: StringBuilder) { to.appendln("</BODY>") diff --git a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt index 870347ab..f869bc75 100644 --- a/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt +++ b/core/src/main/kotlin/Formats/KotlinWebsiteFormatService.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka import com.google.inject.Inject -public class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService, +class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService, signatureGenerator: LanguageService) : JekyllFormatService(locationService, signatureGenerator, "html") { private var needHardLineBreaks = false @@ -13,7 +13,7 @@ public class KotlinWebsiteFormatService @Inject constructor(locationService: Loc to.appendln("layout: api") } - override public fun formatBreadcrumbs(items: Iterable<FormatLink>): String { + override fun formatBreadcrumbs(items: Iterable<FormatLink>): String { items.drop(1) if (items.count() > 1) { @@ -25,7 +25,7 @@ public class KotlinWebsiteFormatService @Inject constructor(locationService: Loc return "" } - override public fun formatCode(code: String): String = if (code.length > 0) "<code>$code</code>" else "" + override fun formatCode(code: String): String = if (code.length > 0) "<code>$code</code>" else "" override fun formatStrikethrough(text: String): String = "<s>$text</s>" @@ -106,7 +106,7 @@ public class KotlinWebsiteFormatService @Inject constructor(locationService: Loc to.appendln("\n</td>") } - override public fun appendBlockCode(to: StringBuilder, line: String, language: String) { + override fun appendBlockCode(to: StringBuilder, line: String, language: String) { if (language.isNotEmpty()) { super.appendBlockCode(to, line, language) } else { diff --git a/core/src/main/kotlin/Formats/MarkdownFormatService.kt b/core/src/main/kotlin/Formats/MarkdownFormatService.kt index 07202b7e..4e16b1a8 100644 --- a/core/src/main/kotlin/Formats/MarkdownFormatService.kt +++ b/core/src/main/kotlin/Formats/MarkdownFormatService.kt @@ -3,16 +3,16 @@ package org.jetbrains.dokka import com.google.inject.Inject -public open class MarkdownFormatService +open class MarkdownFormatService @Inject constructor(locationService: LocationService, signatureGenerator: LanguageService, linkExtension: String = "md") : StructuredFormatService(locationService, signatureGenerator, "md", linkExtension) { - override public fun formatBreadcrumbs(items: Iterable<FormatLink>): String { + override fun formatBreadcrumbs(items: Iterable<FormatLink>): String { return items.map { formatLink(it) }.joinToString(" / ") } - override public fun formatText(text: String): String { + override fun formatText(text: String): String { return text.htmlEscape() } @@ -27,19 +27,19 @@ public open class MarkdownFormatService return text.htmlEscape() } - override public fun formatCode(code: String): String { + override fun formatCode(code: String): String { return "`$code`" } - override public fun formatUnorderedList(text: String): String = text + "\n" - override public fun formatOrderedList(text: String): String = text + "\n" + override fun formatUnorderedList(text: String): String = text + "\n" + override fun formatOrderedList(text: String): String = text + "\n" override fun formatListItem(text: String, kind: ListKind): String { val itemText = if (text.endsWith("\n")) text else text + "\n" return if (kind == ListKind.Unordered) "* $itemText" else "1. $itemText" } - override public fun formatStrong(text: String): String { + override fun formatStrong(text: String): String { return "**$text**" } @@ -55,7 +55,7 @@ public open class MarkdownFormatService return "[$text]($href)" } - override public fun appendLine(to: StringBuilder, text: String) { + override fun appendLine(to: StringBuilder, text: String) { to.appendln(text) } @@ -63,19 +63,19 @@ public open class MarkdownFormatService // no anchors in Markdown } - override public fun appendParagraph(to: StringBuilder, text: String) { + override fun appendParagraph(to: StringBuilder, text: String) { to.appendln() to.appendln(text) to.appendln() } - override public fun appendHeader(to: StringBuilder, text: String, level: Int) { + override fun appendHeader(to: StringBuilder, text: String, level: Int) { appendLine(to) appendLine(to, "${"#".repeat(level)} $text") appendLine(to) } - override public fun appendBlockCode(to: StringBuilder, line: String, language: String) { + override fun appendBlockCode(to: StringBuilder, line: String, language: String) { appendLine(to) to.appendln("``` ${language}") to.appendln(line) diff --git a/core/src/main/kotlin/Formats/OutlineService.kt b/core/src/main/kotlin/Formats/OutlineService.kt index 6626cf51..3c31ba57 100644 --- a/core/src/main/kotlin/Formats/OutlineService.kt +++ b/core/src/main/kotlin/Formats/OutlineService.kt @@ -5,14 +5,14 @@ import java.io.File /** * Service for building the outline of the package contents. */ -public interface OutlineFormatService { +interface OutlineFormatService { fun getOutlineFileName(location: Location): File - public fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) - public fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) + fun appendOutlineHeader(location: Location, node: DocumentationNode, to: StringBuilder) + fun appendOutlineLevel(to: StringBuilder, body: () -> Unit) /** Appends formatted outline to [StringBuilder](to) using specified [location] */ - public fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { + fun appendOutline(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { for (node in nodes) { appendOutlineHeader(location, node, to) if (node.members.any()) { diff --git a/core/src/main/kotlin/Formats/StructuredFormatService.kt b/core/src/main/kotlin/Formats/StructuredFormatService.kt index 324f156a..1d464396 100644 --- a/core/src/main/kotlin/Formats/StructuredFormatService.kt +++ b/core/src/main/kotlin/Formats/StructuredFormatService.kt @@ -11,9 +11,9 @@ enum class ListKind { } abstract class StructuredFormatService(locationService: LocationService, - val languageService: LanguageService, - override val extension: String, - val linkExtension: String = extension) : FormatService { + val languageService: LanguageService, + override val extension: String, + val linkExtension: String = extension) : FormatService { val locationService: LocationService = locationService.withExtension(linkExtension) abstract fun appendBlockCode(to: StringBuilder, line: String, language: String) @@ -51,49 +51,51 @@ abstract class StructuredFormatService(locationService: LocationService, return nodes.map { formatText(location, it, listKind) }.joinToString("") } - open fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String { - return StringBuilder().apply { - when (content) { - is ContentText -> append(formatText(content.text)) - is ContentSymbol -> append(formatSymbol(content.text)) - is ContentKeyword -> append(formatKeyword(content.text)) - is ContentIdentifier -> append(formatIdentifier(content.text, content.kind)) - is ContentNonBreakingSpace -> append(formatNonBreakingSpace()) - is ContentSoftLineBreak -> append(formatSoftLineBreak()) - is ContentIndentedSoftLineBreak -> append(formatIndentedSoftLineBreak()) - is ContentEntity -> append(formatEntity(content.text)) - is ContentStrong -> append(formatStrong(formatText(location, content.children))) - is ContentStrikethrough -> append(formatStrikethrough(formatText(location, content.children))) - is ContentCode -> append(formatCode(formatText(location, content.children))) - is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children))) - is ContentUnorderedList -> append(formatUnorderedList(formatText(location, content.children, ListKind.Unordered))) - is ContentOrderedList -> append(formatOrderedList(formatText(location, content.children, ListKind.Ordered))) - is ContentListItem -> append(formatListItem(formatText(location, content.children), listKind)) - - is ContentNodeLink -> { - val node = content.node - val linkTo = if (node != null) locationHref(location, node) else "#" - val linkText = formatText(location, content.children) - if (linkTo == ".") { - append(linkText) - } else { - append(formatLink(linkText, linkTo)) - } + fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String { + return StringBuilder().apply { formatText(location, content, this, listKind) }.toString() + } + + open fun formatText(location: Location, content: ContentNode, to: StringBuilder, listKind: ListKind = ListKind.Unordered) { + when (content) { + is ContentText -> to.append(formatText(content.text)) + is ContentSymbol -> to.append(formatSymbol(content.text)) + is ContentKeyword -> to.append(formatKeyword(content.text)) + is ContentIdentifier -> to.append(formatIdentifier(content.text, content.kind)) + is ContentNonBreakingSpace -> to.append(formatNonBreakingSpace()) + is ContentSoftLineBreak -> to.append(formatSoftLineBreak()) + is ContentIndentedSoftLineBreak -> to.append(formatIndentedSoftLineBreak()) + is ContentEntity -> to.append(formatEntity(content.text)) + is ContentStrong -> to.append(formatStrong(formatText(location, content.children))) + is ContentStrikethrough -> to.append(formatStrikethrough(formatText(location, content.children))) + is ContentCode -> to.append(formatCode(formatText(location, content.children))) + is ContentEmphasis -> to.append(formatEmphasis(formatText(location, content.children))) + is ContentUnorderedList -> to.append(formatUnorderedList(formatText(location, content.children, ListKind.Unordered))) + is ContentOrderedList -> to.append(formatOrderedList(formatText(location, content.children, ListKind.Ordered))) + is ContentListItem -> to.append(formatListItem(formatText(location, content.children), listKind)) + + is ContentNodeLink -> { + val node = content.node + val linkTo = if (node != null) locationHref(location, node) else "#" + val linkText = formatText(location, content.children) + if (linkTo == ".") { + to.append(linkText) + } else { + to.append(formatLink(linkText, linkTo)) } - is ContentExternalLink -> { - val linkText = formatText(location, content.children) - if (content.href == ".") { - append(linkText) - } else { - append(formatLink(linkText, content.href)) - } + } + is ContentExternalLink -> { + val linkText = formatText(location, content.children) + if (content.href == ".") { + to.append(linkText) + } else { + to.append(formatLink(linkText, content.href)) } - is ContentParagraph -> appendParagraph(this, formatText(location, content.children)) - is ContentBlockCode -> appendBlockCode(this, formatText(location, content.children), content.language) - is ContentHeading -> appendHeader(this, formatText(location, content.children), content.level) - is ContentBlock -> append(formatText(location, content.children)) } - }.toString() + is ContentParagraph -> appendParagraph(to, formatText(location, content.children)) + is ContentBlockCode -> appendBlockCode(to, formatText(location, content.children), content.language) + is ContentHeading -> appendHeader(to, formatText(location, content.children), content.level) + is ContentBlock -> to.append(formatText(location, content.children)) + } } open fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension) @@ -103,51 +105,15 @@ abstract class StructuredFormatService(locationService: LocationService, } fun locationHref(from: Location, to: DocumentationNode): String { - val topLevelPage = to.references(DocumentationReference.Kind.TopLevelPage).singleOrNull()?.to + val topLevelPage = to.references(RefKind.TopLevelPage).singleOrNull()?.to if (topLevelPage != null) { return from.relativePathTo(locationService.location(topLevelPage), to.name) } return from.relativePathTo(locationService.location(to)) } - fun appendDocumentation(location: Location, to: StringBuilder, overloads: Iterable<DocumentationNode>) { - val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content } - - if (breakdownBySummary.size == 1) { - formatOverloadGroup(breakdownBySummary.values.single(), location, to) - } - else { - for ((summary, items) in breakdownBySummary) { - appendAsOverloadGroup(to) { - formatOverloadGroup(items, location, to) - } - } - } - } - - private fun formatOverloadGroup(items: MutableList<DocumentationNode>, location: Location, to: StringBuilder) { - items.forEach { - val rendered = languageService.render(it) - appendAsSignature(to, rendered) { - to.append(formatCode(formatText(location, rendered))) - it.appendSourceLink(to) - } - it.appendOverrides(to) - it.appendDeprecation(location, to) - } - // All items have exactly the same documentation, so we can use any item to render it - val item = items.first() - item.details(DocumentationNode.Kind.OverloadGroupNote).forEach { - to.append(formatText(location, it.content)) - } - to.append(formatText(location, item.content.summary)) - appendDescription(location, to, item) - appendLine(to) - appendLine(to) - } - private fun DocumentationNode.isModuleOrPackage(): Boolean = - kind == DocumentationNode.Kind.Module || kind == DocumentationNode.Kind.Package + kind == NodeKind.Module || kind == NodeKind.Package protected open fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) { block() @@ -157,94 +123,218 @@ abstract class StructuredFormatService(locationService: LocationService, block() } - fun appendDescription(location: Location, to: StringBuilder, node: DocumentationNode) { - if (node.content.description != ContentEmpty) { - appendLine(to, formatText(location, node.content.description)) - appendLine(to) - } - node.content.getSectionsWithSubjects().forEach { - appendSectionWithSubject(it.key, location, it.value, to) - } + fun Content.getSectionsWithSubjects(): Map<String, List<ContentSection>> = + sections.filter { it.subjectName != null }.groupBy { it.tag } - for (section in node.content.sections.filter { it.subjectName == null }) { - appendLine(to, formatStrong(formatText(section.tag))) - appendLine(to, formatText(location, section)) + private fun ContentNode.signatureToText(location: Location): String { + return if (this is ContentBlock && this.isEmpty()) { + "" + } else { + val signatureAsCode = ContentCode() + signatureAsCode.append(this) + formatText(location, signatureAsCode) } } - fun Content.getSectionsWithSubjects(): Map<String, List<ContentSection>> = - sections.filter { it.subjectName != null }.groupBy { it.tag } + open inner class PageBuilder(val location: Location, val to: StringBuilder, val nodes: Iterable<DocumentationNode>) { + open fun build() { + val breakdownByLocation = nodes.groupBy { node -> + formatBreadcrumbs(node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }) + } - fun appendSectionWithSubject(title: String, location: Location, subjectSections: List<ContentSection>, to: StringBuilder) { - appendHeader(to, title, 3) - subjectSections.forEach { - val subjectName = it.subjectName - if (subjectName != null) { - appendAnchor(to, subjectName) - to.append(formatCode(subjectName)).append(" - ") - to.append(formatText(location, it)) + for ((breadcrumbs, items) in breakdownByLocation) { + appendLine(to, breadcrumbs) appendLine(to) + appendLocation(items.filter { it.kind != NodeKind.ExternalClass }) } } - } - private fun DocumentationNode.appendOverrides(to: StringBuilder) { - overrides.forEach { - to.append("Overrides ") - val location = locationService.relativePathToLocation(this, it) - appendLine(to, formatLink(FormatLink(it.owner!!.name + "." + it.name, location))) + private fun appendLocation(nodes: Iterable<DocumentationNode>) { + val singleNode = nodes.singleOrNull() + if (singleNode != null && singleNode.isModuleOrPackage()) { + if (singleNode.kind == NodeKind.Package) { + val packageName = if (singleNode.name.isEmpty()) "<root>" else singleNode.name + appendHeader(to, "Package " + formatText(packageName), 2) + } + formatText(location, singleNode.content, to) + } else { + val breakdownByName = nodes.groupBy { node -> node.name } + for ((name, items) in breakdownByName) { + appendHeader(to, formatText(name)) + appendDocumentation(items) + } + } } - } - private fun DocumentationNode.appendDeprecation(location: Location, to: StringBuilder) { - if (deprecation != null) { - val deprecationParameter = deprecation!!.details(DocumentationNode.Kind.Parameter).firstOrNull() - val deprecationValue = deprecationParameter?.details(DocumentationNode.Kind.Value)?.firstOrNull() - if (deprecationValue != null) { - to.append(formatStrong("Deprecated:")).append(" ") - appendLine(to, formatText(deprecationValue.name.removeSurrounding("\""))) - appendLine(to) - } else if (deprecation?.content != Content.Empty) { - to.append(formatStrong("Deprecated:")).append(" ") - to.append(formatText(location, deprecation!!.content)) + private fun appendDocumentation(overloads: Iterable<DocumentationNode>) { + val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content } + + if (breakdownBySummary.size == 1) { + formatOverloadGroup(breakdownBySummary.values.single()) } else { - appendLine(to, formatStrong("Deprecated")) - appendLine(to) + for ((summary, items) in breakdownBySummary) { + appendAsOverloadGroup(to) { + formatOverloadGroup(items) + } + } } } - } - private fun DocumentationNode.appendSourceLink(to: StringBuilder) { - val sourceUrl = details(DocumentationNode.Kind.SourceUrl).firstOrNull() - if (sourceUrl != null) { - to.append(" ") - appendLine(to, formatLink("(source)", sourceUrl.name)) - } else { + private fun formatOverloadGroup(items: MutableList<DocumentationNode>) { + items.forEach { + val rendered = languageService.render(it) + appendAsSignature(to, rendered) { + to.append(formatCode(formatText(location, rendered))) + it.appendSourceLink() + } + it.appendOverrides() + it.appendDeprecation() + } + // All items have exactly the same documentation, so we can use any item to render it + val item = items.first() + item.details(NodeKind.OverloadGroupNote).forEach { + formatText(location, it.content, to) + } + formatText(location, item.content.summary, to) + item.appendDescription() + appendLine(to) appendLine(to) } - } - fun appendLocation(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { - val singleNode = nodes.singleOrNull() - if (singleNode != null && singleNode.isModuleOrPackage()) { - if (singleNode.kind == DocumentationNode.Kind.Package) { - appendHeader(to, "Package " + formatText(singleNode.name), 2) + private fun DocumentationNode.appendSourceLink() { + val sourceUrl = details(NodeKind.SourceUrl).firstOrNull() + if (sourceUrl != null) { + to.append(" ") + appendLine(to, formatLink("(source)", sourceUrl.name)) + } else { + appendLine(to) } - to.append(formatText(location, singleNode.content)) - } else { - val breakdownByName = nodes.groupBy { node -> node.name } - for ((name, items) in breakdownByName) { - appendHeader(to, formatText(name)) - appendDocumentation(location, to, items) + } + + private fun DocumentationNode.appendOverrides() { + overrides.forEach { + to.append("Overrides ") + val location = locationService.relativePathToLocation(this, it) + appendLine(to, formatLink(FormatLink(it.owner!!.name + "." + it.name, location))) + } + } + + private fun DocumentationNode.appendDeprecation() { + if (deprecation != null) { + val deprecationParameter = deprecation!!.details(NodeKind.Parameter).firstOrNull() + val deprecationValue = deprecationParameter?.details(NodeKind.Value)?.firstOrNull() + if (deprecationValue != null) { + to.append(formatStrong("Deprecated:")).append(" ") + appendLine(to, formatText(deprecationValue.name.removeSurrounding("\""))) + appendLine(to) + } else if (deprecation?.content != Content.Empty) { + to.append(formatStrong("Deprecated:")).append(" ") + formatText(location, deprecation!!.content, to) + } else { + appendLine(to, formatStrong("Deprecated")) + appendLine(to) + } + } + } + + private fun DocumentationNode.appendDescription() { + if (content.description != ContentEmpty) { + appendLine(to, formatText(location, content.description)) + appendLine(to) + } + content.getSectionsWithSubjects().forEach { + appendSectionWithSubject(it.key, it.value) + } + + for (section in content.sections.filter { it.subjectName == null }) { + appendLine(to, formatStrong(formatText(section.tag))) + appendLine(to, formatText(location, section)) + } + } + + fun appendSectionWithSubject(title: String, subjectSections: List<ContentSection>) { + appendHeader(to, title, 3) + var first: Boolean = true + subjectSections.forEach { + val subjectName = it.subjectName + if (subjectName != null) { + if (first) { + first = false + } + else { + appendLine(to) + } + + appendAnchor(to, subjectName) + to.append(formatCode(subjectName)).append(" - ") + formatText(location, it, to) + appendLine(to) + } } } } - private fun appendSection(location: Location, caption: String, nodes: List<DocumentationNode>, node: DocumentationNode, to: StringBuilder) { - if (nodes.any()) { + inner class SingleNodePageBuilder(location: Location, to: StringBuilder, val node: DocumentationNode) + : PageBuilder(location, to, listOf(node)) { + + override fun build() { + super.build() + + if (node.kind == NodeKind.ExternalClass) { + appendSection("Extensions for ${node.name}", node.members) + return + } + + appendSection("Packages", node.members(NodeKind.Package)) + appendSection("Types", node.members.filter { it.kind in NodeKind.classLike && it.kind != NodeKind.AnnotationClass && it.kind != NodeKind.Exception }) + appendSection("Annotations", node.members(NodeKind.AnnotationClass)) + appendSection("Exceptions", node.members(NodeKind.Exception)) + appendSection("Extensions for External Classes", node.members(NodeKind.ExternalClass)) + appendSection("Enum Values", node.members(NodeKind.EnumItem)) + appendSection("Constructors", node.members(NodeKind.Constructor)) + appendSection("Properties", node.members(NodeKind.Property)) + appendSection("Inherited Properties", node.inheritedMembers(NodeKind.Property)) + appendSection("Functions", node.members(NodeKind.Function)) + appendSection("Inherited Functions", node.inheritedMembers(NodeKind.Function)) + appendSection("Companion Object Properties", node.members(NodeKind.CompanionObjectProperty)) + appendSection("Inherited Companion Object Properties", node.inheritedCompanionObjectMembers(NodeKind.Property)) + appendSection("Companion Object Functions", node.members(NodeKind.CompanionObjectFunction)) + appendSection("Inherited Companion Object Functions", node.inheritedCompanionObjectMembers(NodeKind.Function)) + appendSection("Other members", node.members.filter { + it.kind !in setOf( + NodeKind.Class, + NodeKind.Interface, + NodeKind.Enum, + NodeKind.Object, + NodeKind.AnnotationClass, + NodeKind.Exception, + NodeKind.Constructor, + NodeKind.Property, + NodeKind.Package, + NodeKind.Function, + NodeKind.CompanionObjectProperty, + NodeKind.CompanionObjectFunction, + NodeKind.ExternalClass, + NodeKind.EnumItem + ) + }) + + val allExtensions = node.extensions + appendSection("Extension Properties", allExtensions.filter { it.kind == NodeKind.Property }) + appendSection("Extension Functions", allExtensions.filter { it.kind == NodeKind.Function }) + appendSection("Companion Object Extension Properties", allExtensions.filter { it.kind == NodeKind.CompanionObjectProperty }) + appendSection("Companion Object Extension Functions", allExtensions.filter { it.kind == NodeKind.CompanionObjectFunction }) + appendSection("Inheritors", + node.inheritors.filter { it.kind != NodeKind.EnumItem }) + appendSection("Links", node.links) + } + + private fun appendSection(caption: String, members: List<DocumentationNode>) { + if (members.isEmpty()) return + appendHeader(to, caption, 3) - val children = nodes.sortedBy { it.name } + val children = members.sortedBy { it.name } val membersMap = children.groupBy { link(node, it) } appendTable(to) { @@ -257,7 +347,7 @@ abstract class StructuredFormatService(locationService: LocationService, appendTableCell(to) { val breakdownBySummary = members.groupBy { formatText(location, it.summary) } for ((summary, items) in breakdownBySummary) { - appendSummarySignatures(items, location, to) + appendSummarySignatures(items) if (!summary.isEmpty()) { to.append(summary) } @@ -268,108 +358,34 @@ abstract class StructuredFormatService(locationService: LocationService, } } } - } - private fun appendSummarySignatures(items: List<DocumentationNode>, location: Location, to: StringBuilder) { - val summarySignature = languageService.summarizeSignatures(items) - if (summarySignature != null) { - appendAsSignature(to, summarySignature) { - appendLine(to, summarySignature.signatureToText(location)) + private fun appendSummarySignatures(items: List<DocumentationNode>) { + val summarySignature = languageService.summarizeSignatures(items) + if (summarySignature != null) { + appendAsSignature(to, summarySignature) { + appendLine(to, summarySignature.signatureToText(location)) + } + return } - return - } - val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) } - renderedSignatures.subList(0, renderedSignatures.size - 1).forEach { - appendAsSignature(to, it) { - appendLine(to, it.signatureToText(location)) + val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) } + renderedSignatures.subList(0, renderedSignatures.size - 1).forEach { + appendAsSignature(to, it) { + appendLine(to, it.signatureToText(location)) + } + } + appendAsSignature(to, renderedSignatures.last()) { + to.append(renderedSignatures.last().signatureToText(location)) } - } - appendAsSignature(to, renderedSignatures.last()) { - to.append(renderedSignatures.last().signatureToText(location)) - } - } - - private fun ContentNode.signatureToText(location: Location): String { - return if (this is ContentBlock && this.isEmpty()) { - "" - } else { - val signatureAsCode = ContentCode() - signatureAsCode.append(this) - formatText(location, signatureAsCode) } } override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) { - val breakdownByLocation = nodes.groupBy { node -> - formatBreadcrumbs(node.path.filterNot { it.name.isEmpty() }.map { link(node, it) }) - } - - for ((breadcrumbs, items) in breakdownByLocation) { - appendLine(to, breadcrumbs) - appendLine(to) - appendLocation(location, to, items.filter { it.kind != DocumentationNode.Kind.ExternalClass }) - } - - for (node in nodes) { - if (node.kind == DocumentationNode.Kind.ExternalClass) { - appendSection(location, "Extensions for ${node.name}", node.members, node, to) - continue - } - - appendSection(location, "Packages", node.members(DocumentationNode.Kind.Package), node, to) - appendSection(location, "Types", node.members.filter { it.kind in DocumentationNode.Kind.classLike }, node, to) - appendSection(location, "Extensions for External Classes", node.members(DocumentationNode.Kind.ExternalClass), node, to) - appendSection(location, "Enum Values", node.members(DocumentationNode.Kind.EnumItem), node, to) - appendSection(location, "Constructors", node.members(DocumentationNode.Kind.Constructor), node, to) - appendSection(location, "Properties", node.members(DocumentationNode.Kind.Property), node, to) - appendSection(location, "Inherited Properties", node.inheritedMembers(DocumentationNode.Kind.Property), node, to) - appendSection(location, "Functions", node.members(DocumentationNode.Kind.Function), node, to) - appendSection(location, "Inherited Functions", node.inheritedMembers(DocumentationNode.Kind.Function), node, to) - appendSection(location, "Companion Object Properties", node.members(DocumentationNode.Kind.CompanionObjectProperty), node, to) - appendSection(location, "Companion Object Functions", node.members(DocumentationNode.Kind.CompanionObjectFunction), node, to) - appendSection(location, "Other members", node.members.filter { - it.kind !in setOf( - DocumentationNode.Kind.Class, - DocumentationNode.Kind.Interface, - DocumentationNode.Kind.Enum, - DocumentationNode.Kind.Object, - DocumentationNode.Kind.AnnotationClass, - DocumentationNode.Kind.Constructor, - DocumentationNode.Kind.Property, - DocumentationNode.Kind.Package, - DocumentationNode.Kind.Function, - DocumentationNode.Kind.CompanionObjectProperty, - DocumentationNode.Kind.CompanionObjectFunction, - DocumentationNode.Kind.ExternalClass, - DocumentationNode.Kind.EnumItem - ) - }, node, to) - - val allExtensions = collectAllExtensions(node) - appendSection(location, "Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.Property }, node, to) - appendSection(location, "Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.Function }, node, to) - appendSection(location, "Companion Object Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectProperty }, node, to) - appendSection(location, "Companion Object Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectFunction }, node, to) - appendSection(location, "Inheritors", - node.inheritors.filter { it.kind != DocumentationNode.Kind.EnumItem }, node, to) - appendSection(location, "Links", node.links, node, to) - + val singleNode = nodes.singleOrNull() + if (singleNode != null) { + SingleNodePageBuilder(location, to, singleNode).build() } - } - - private fun collectAllExtensions(node: DocumentationNode): Collection<DocumentationNode> { - val result = LinkedHashSet<DocumentationNode>() - val visited = hashSetOf<DocumentationNode>() - - fun collect(node: DocumentationNode) { - if (!visited.add(node)) return - result.addAll(node.extensions) - node.references(DocumentationReference.Kind.Superclass).forEach { collect(it.to) } + else { + PageBuilder(location, to, nodes).build() } - - collect(node) - - return result - } -}
\ No newline at end of file +} diff --git a/core/src/main/kotlin/Generation/ConsoleGenerator.kt b/core/src/main/kotlin/Generation/ConsoleGenerator.kt index 803a16e4..301f86b9 100644 --- a/core/src/main/kotlin/Generation/ConsoleGenerator.kt +++ b/core/src/main/kotlin/Generation/ConsoleGenerator.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka -public class ConsoleGenerator(val signatureGenerator: LanguageService, val locationService: LocationService) { +class ConsoleGenerator(val signatureGenerator: LanguageService, val locationService: LocationService) { val IndentStep = " " - public fun generate(node: DocumentationNode, indent: String = "") { + fun generate(node: DocumentationNode, indent: String = "") { println("@${locationService.location(node).path}") generateHeader(node, indent) //generateDetails(node, indent) @@ -11,7 +11,7 @@ public class ConsoleGenerator(val signatureGenerator: LanguageService, val locat generateLinks(node, indent) } - public fun generateHeader(node: DocumentationNode, indent: String = "") { + fun generateHeader(node: DocumentationNode, indent: String = "") { println(indent + signatureGenerator.render(node)) val docString = node.content.toString() if (!docString.isEmpty()) @@ -19,19 +19,19 @@ public class ConsoleGenerator(val signatureGenerator: LanguageService, val locat println() } - public fun generateMembers(node: DocumentationNode, indent: String = "") { + fun generateMembers(node: DocumentationNode, indent: String = "") { val items = node.members.sortedBy { it.name } for (child in items) generate(child, indent + IndentStep) } - public fun generateDetails(node: DocumentationNode, indent: String = "") { + fun generateDetails(node: DocumentationNode, indent: String = "") { val items = node.details for (child in items) generate(child, indent + " ") } - public fun generateLinks(node: DocumentationNode, indent: String = "") { + fun generateLinks(node: DocumentationNode, indent: String = "") { val items = node.links if (items.isEmpty()) return diff --git a/core/src/main/kotlin/Generation/FileGenerator.kt b/core/src/main/kotlin/Generation/FileGenerator.kt index e3d1d1fe..86ebd6b7 100644 --- a/core/src/main/kotlin/Generation/FileGenerator.kt +++ b/core/src/main/kotlin/Generation/FileGenerator.kt @@ -6,7 +6,7 @@ import java.io.FileOutputStream import java.io.IOException import java.io.OutputStreamWriter -public class FileGenerator @Inject constructor(val locationService: FileLocationService) : Generator { +class FileGenerator @Inject constructor(val locationService: FileLocationService) : Generator { @set:Inject(optional = true) var outlineService: OutlineFormatService? = null @set:Inject(optional = true) lateinit var formatService: FormatService diff --git a/core/src/main/kotlin/Generation/Generator.kt b/core/src/main/kotlin/Generation/Generator.kt index ac10a6a5..83ddd04f 100644 --- a/core/src/main/kotlin/Generation/Generator.kt +++ b/core/src/main/kotlin/Generation/Generator.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka -public interface Generator { +interface Generator { fun buildPages(nodes: Iterable<DocumentationNode>) fun buildOutlines(nodes: Iterable<DocumentationNode>) fun buildSupportFiles() diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt index 3c9875cd..67bf1f08 100644 --- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt +++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka import com.google.inject.Inject import com.intellij.psi.* -import org.jetbrains.dokka.DocumentationNode.Kind +import com.intellij.psi.util.InheritanceUtil fun getSignature(element: PsiElement?) = when(element) { is PsiClass -> element.qualifiedName @@ -69,11 +69,11 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { fun link(node: DocumentationNode, element: PsiElement?) { val qualifiedName = getSignature(element) if (qualifiedName != null) { - refGraph.link(node, qualifiedName, DocumentationReference.Kind.Link) + refGraph.link(node, qualifiedName, RefKind.Link) } } - fun link(element: PsiElement?, node: DocumentationNode, kind: DocumentationReference.Kind) { + fun link(element: PsiElement?, node: DocumentationNode, kind: RefKind) { val qualifiedName = getSignature(element) if (qualifiedName != null) { refGraph.link(qualifiedName, node, kind) @@ -81,7 +81,7 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { } fun nodeForElement(element: PsiNamedElement, - kind: Kind, + kind: NodeKind, name: String = element.name ?: "<anonymous>"): DocumentationNode { val (docComment, deprecatedContent) = docParser.parseDocumentation(element) val node = DocumentationNode(name, docComment, kind) @@ -92,17 +92,17 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { modifierList.annotations.filter { !ignoreAnnotation(it) }.forEach { val annotation = it.build() node.append(annotation, - if (it.qualifiedName == "java.lang.Deprecated") DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation) + if (it.qualifiedName == "java.lang.Deprecated") RefKind.Deprecation else RefKind.Annotation) } } } if (deprecatedContent != null) { - val deprecationNode = DocumentationNode("", deprecatedContent, Kind.Modifier) - node.append(deprecationNode, DocumentationReference.Kind.Deprecation) + 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")), Kind.Modifier) - node.append(deprecationNode, DocumentationReference.Kind.Deprecation) + val deprecationNode = DocumentationNode("", Content.of(ContentText("Deprecated")), NodeKind.Modifier) + node.append(deprecationNode, RefKind.Deprecation) } return node } @@ -113,7 +113,7 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { } fun <T : Any> DocumentationNode.appendChildren(elements: Array<T>, - kind: DocumentationReference.Kind = DocumentationReference.Kind.Member, + kind: RefKind = RefKind.Member, buildFn: T.() -> DocumentationNode) { elements.forEach { if (!skipElement(it)) { @@ -132,24 +132,25 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { element is PsiDocCommentOwner && element.docComment?.let { it.findTagByName("suppress") != null } ?: false fun <T : Any> DocumentationNode.appendMembers(elements: Array<T>, buildFn: T.() -> DocumentationNode) = - appendChildren(elements, DocumentationReference.Kind.Member, buildFn) + appendChildren(elements, RefKind.Member, buildFn) fun <T : Any> DocumentationNode.appendDetails(elements: Array<T>, buildFn: T.() -> DocumentationNode) = - appendChildren(elements, DocumentationReference.Kind.Detail, buildFn) + appendChildren(elements, RefKind.Detail, buildFn) fun PsiClass.build(): DocumentationNode { val kind = when { - isInterface -> DocumentationNode.Kind.Interface - isEnum -> DocumentationNode.Kind.Enum - isAnnotationType -> DocumentationNode.Kind.AnnotationClass - else -> DocumentationNode.Kind.Class + isInterface -> NodeKind.Interface + isEnum -> NodeKind.Enum + isAnnotationType -> NodeKind.AnnotationClass + isException() -> NodeKind.Exception + else -> NodeKind.Class } val node = nodeForElement(this, kind) superTypes.filter { !ignoreSupertype(it) }.forEach { - node.appendType(it, Kind.Supertype) + node.appendType(it, NodeKind.Supertype) val superClass = it.resolve() if (superClass != null) { - link(superClass, node, DocumentationReference.Kind.Inheritor) + link(superClass, node, RefKind.Inheritor) } } node.appendDetails(typeParameters) { build() } @@ -160,6 +161,8 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { return node } + fun PsiClass.isException() = InheritanceUtil.isInheritor(this, "java.lang.Throwable") + fun ignoreSupertype(psiType: PsiClassType): Boolean = psiType.isClass("java.lang.Enum") || psiType.isClass("java.lang.Object") @@ -180,9 +183,9 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { return node } - private fun PsiField.nodeKind(): Kind = when { - this is PsiEnumConstant -> Kind.EnumItem - else -> Kind.Field + private fun PsiField.nodeKind(): NodeKind = when { + this is PsiEnumConstant -> NodeKind.EnumItem + else -> NodeKind.Field } fun PsiMethod.build(): DocumentationNode { @@ -198,24 +201,24 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { return node } - private fun PsiMethod.nodeKind(): Kind = when { - isConstructor -> Kind.Constructor - else -> Kind.Function + private fun PsiMethod.nodeKind(): NodeKind = when { + isConstructor -> NodeKind.Constructor + else -> NodeKind.Function } fun PsiParameter.build(): DocumentationNode { - val node = nodeForElement(this, Kind.Parameter) + val node = nodeForElement(this, NodeKind.Parameter) node.appendType(type) if (type is PsiEllipsisType) { - node.appendTextNode("vararg", Kind.Modifier, DocumentationReference.Kind.Detail) + node.appendTextNode("vararg", NodeKind.Modifier, RefKind.Detail) } return node } fun PsiTypeParameter.build(): DocumentationNode { - val node = nodeForElement(this, Kind.TypeParameter) - extendsListTypes.forEach { node.appendType(it, Kind.UpperBound) } - implementsListTypes.forEach { node.appendType(it, Kind.UpperBound) } + val node = nodeForElement(this, NodeKind.TypeParameter) + extendsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) } + implementsListTypes.forEach { node.appendType(it, NodeKind.UpperBound) } return node } @@ -224,42 +227,42 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder { PsiModifier.MODIFIERS.forEach { if (modifierList.hasExplicitModifier(it)) { - appendTextNode(it, Kind.Modifier) + appendTextNode(it, NodeKind.Modifier) } } } - fun DocumentationNode.appendType(psiType: PsiType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) { + fun DocumentationNode.appendType(psiType: PsiType?, kind: NodeKind = NodeKind.Type) { if (psiType == null) { return } - append(psiType.build(kind), DocumentationReference.Kind.Detail) + append(psiType.build(kind), RefKind.Detail) } - fun PsiType.build(kind: DocumentationNode.Kind = DocumentationNode.Kind.Type): DocumentationNode { + fun PsiType.build(kind: NodeKind = NodeKind.Type): DocumentationNode { val name = mapTypeName(this) val node = DocumentationNode(name, Content.Empty, kind) if (this is PsiClassType) { - node.appendDetails(parameters) { build(Kind.Type) } + node.appendDetails(parameters) { build(NodeKind.Type) } link(node, resolve()) } if (this is PsiArrayType && this !is PsiEllipsisType) { - node.append(componentType.build(Kind.Type), DocumentationReference.Kind.Detail) + node.append(componentType.build(NodeKind.Type), RefKind.Detail) } return node } fun PsiAnnotation.build(): DocumentationNode { - val node = DocumentationNode(nameReferenceElement?.text ?: "<?>", Content.Empty, DocumentationNode.Kind.Annotation) + val node = DocumentationNode(nameReferenceElement?.text ?: "<?>", Content.Empty, NodeKind.Annotation) parameterList.attributes.forEach { - val parameter = DocumentationNode(it.name ?: "value", Content.Empty, DocumentationNode.Kind.Parameter) + val parameter = DocumentationNode(it.name ?: "value", Content.Empty, NodeKind.Parameter) val value = it.value if (value != null) { val valueText = (value as? PsiLiteralExpression)?.value as? String ?: value.text - val valueNode = DocumentationNode(valueText, Content.Empty, DocumentationNode.Kind.Value) - parameter.append(valueNode, DocumentationReference.Kind.Detail) + val valueNode = DocumentationNode(valueText, Content.Empty, NodeKind.Value) + parameter.append(valueNode, RefKind.Detail) } - node.append(parameter, DocumentationReference.Kind.Detail) + node.append(parameter, RefKind.Detail) } return node } diff --git a/core/src/main/kotlin/Kotlin/ContentBuilder.kt b/core/src/main/kotlin/Kotlin/ContentBuilder.kt index 39e8d8ce..ea07acbc 100644 --- a/core/src/main/kotlin/Kotlin/ContentBuilder.kt +++ b/core/src/main/kotlin/Kotlin/ContentBuilder.kt @@ -5,7 +5,7 @@ import org.intellij.markdown.MarkdownTokenTypes import org.intellij.markdown.html.entities.EntityConverter import java.util.* -public fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock, inline: Boolean = false): MutableContent { +fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock, inline: Boolean = false): MutableContent { val result = MutableContent() if (inline) { buildInlineContentTo(tree, result, linkResolver) @@ -16,7 +16,7 @@ public fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlo return result } -public fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { +fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { // println(tree.toTestString()) val nodeStack = ArrayDeque<ContentBlock>() nodeStack.push(target) @@ -131,7 +131,7 @@ private fun MarkdownNode.getLabelText() = children.filter { it.type == MarkdownT private fun keepWhitespace(node: ContentNode) = node is ContentParagraph || node is ContentSection -public fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { +fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree) inlineContent.forEach { buildContentTo(it, target, linkResolver) diff --git a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt index 2569bc71..c1c301f2 100644 --- a/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt +++ b/core/src/main/kotlin/Kotlin/DeclarationLinkResolver.kt @@ -1,9 +1,15 @@ package org.jetbrains.dokka import com.google.inject.Inject +import com.intellij.psi.PsiMethod import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.source.PsiSourceElement class DeclarationLinkResolver @Inject constructor(val resolutionFacade: DokkaResolutionFacade, @@ -20,6 +26,10 @@ class DeclarationLinkResolver // don't include unresolved links in generated doc // assume that if an href doesn't contain '/', it's not an attempt to reference an external file if (symbol != null) { + val jdkHref = buildJdkLink(symbol) + if (jdkHref != null) { + return ContentExternalLink(jdkHref) + } return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) }) } if ("/" in href) { @@ -40,4 +50,26 @@ class DeclarationLinkResolver return symbol } + fun buildJdkLink(symbol: DeclarationDescriptor): String? { + if (symbol is JavaClassDescriptor) { + val fqName = DescriptorUtils.getFqName(symbol) + if (fqName.startsWith(Name.identifier("java")) || fqName.startsWith(Name.identifier("javax"))) { + return javadocRoot + fqName.asString().replace(".", "/") + ".html" + } + } + else if (symbol is JavaMethodDescriptor) { + val containingClass = symbol.containingDeclaration as? JavaClassDescriptor ?: return null + val containingClassLink = buildJdkLink(containingClass) + if (containingClassLink != null) { + val psi = (symbol.original.source as? PsiSourceElement)?.psi as? PsiMethod + if (psi != null) { + val params = psi.parameterList.parameters.joinToString { it.type.canonicalText } + return containingClassLink + "#" + symbol.name + "(" + params + ")" + } + } + } + return null + } + + private val javadocRoot = "http://docs.oracle.com/javase/6/docs/api/" }
\ No newline at end of file diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt index 8a15e9bf..7d39e5ac 100644 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt @@ -122,8 +122,8 @@ class DescriptorDocumentationParser val parseResult = JavadocParser(refGraph).parseDocumentation(psi as PsiNamedElement) return parseResult.content to { node -> parseResult.deprecatedContent?.let { - val deprecationNode = DocumentationNode("", it, DocumentationNode.Kind.Modifier) - node.append(deprecationNode, DocumentationReference.Kind.Deprecation) + val deprecationNode = DocumentationNode("", it, NodeKind.Modifier) + node.append(deprecationNode, RefKind.Deprecation) } } } diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt index 6551ded6..4694bcdf 100644 --- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt @@ -3,7 +3,6 @@ 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.DocumentationNode.Kind import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* @@ -20,11 +19,11 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.ConstantValue -import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation +import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.source.PsiSourceElement @@ -32,26 +31,34 @@ import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection - -public data class DocumentationOptions(val outputDir: String, - val outputFormat: String, - val includeNonPublic: Boolean = false, - val reportUndocumented: Boolean = true, - val skipEmptyPackages: Boolean = true, - val skipDeprecated: Boolean = false, - val sourceLinks: List<SourceLinkDefinition>) - -private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: DeclarationDescriptor): Boolean { - val package1 = DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor::class.java) - val package2 = DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor::class.java) - return package1 != null && package2 != null && package1.fqName == package2.fqName +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.types.typeUtil.supertypes + +data class DocumentationOptions(val outputDir: String, + val outputFormat: String, + val includeNonPublic: Boolean = false, + val reportUndocumented: Boolean = true, + val skipEmptyPackages: Boolean = true, + val skipDeprecated: Boolean = false, + val sourceLinks: List<SourceLinkDefinition>) + +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>) + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName>) } class DocumentationBuilder @@ -59,7 +66,8 @@ class DocumentationBuilder val descriptorDocumentationParser: DescriptorDocumentationParser, val options: DocumentationOptions, val refGraph: NodeReferenceGraph, - val logger: DokkaLogger) + val logger: DokkaLogger, + val linkResolver: DeclarationLinkResolver) { val visibleToDocumentation = setOf(Visibilities.PROTECTED, Visibilities.PUBLIC) val boringBuiltinClasses = setOf( @@ -70,11 +78,11 @@ class DocumentationBuilder KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.OVERRIDE_KEYWORD) - fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) { + fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) { refGraph.link(node, descriptor.signature(), kind) } - fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: DocumentationReference.Kind) { + fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: RefKind) { if (fromDescriptor != null && toDescriptor != null) { refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind) } @@ -84,8 +92,8 @@ class DocumentationBuilder refGraph.register(descriptor.signature(), node) } - fun <T> nodeForDescriptor(descriptor: T, kind: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named { - val (doc, callback) = descriptorDocumentationParser.parseDocumentationAndDetails(descriptor, kind == Kind.Parameter) + fun <T> nodeForDescriptor(descriptor: T, kind: NodeKind): DocumentationNode where T : DeclarationDescriptor, T : Named { + val (doc, callback) = descriptorDocumentationParser.parseDocumentationAndDetails(descriptor, kind == NodeKind.Parameter) val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor) callback(node) return node @@ -110,22 +118,22 @@ class DocumentationBuilder } } val modifier = modality.name.toLowerCase() - appendTextNode(modifier, DocumentationNode.Kind.Modifier) + appendTextNode(modifier, NodeKind.Modifier) } fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) { val modifier = descriptor.visibility.normalize().displayName - appendTextNode(modifier, DocumentationNode.Kind.Modifier) + appendTextNode(modifier, NodeKind.Modifier) } fun DocumentationNode.appendSupertypes(descriptor: ClassDescriptor) { val superTypes = descriptor.typeConstructor.supertypes for (superType in superTypes) { if (!ignoreSupertype(superType)) { - appendType(superType, DocumentationNode.Kind.Supertype) + appendType(superType, NodeKind.Supertype) val superclass = superType?.constructor?.declarationDescriptor - link(superclass, descriptor, DocumentationReference.Kind.Inheritor) - link(descriptor, superclass, DocumentationReference.Kind.Superclass) + link(superclass, descriptor, RefKind.Inheritor) + link(descriptor, superclass, RefKind.Superclass) } } } @@ -139,16 +147,16 @@ class DocumentationBuilder return false } - fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) { + fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) { if (projection.isStarProjection) { - appendTextNode("*", Kind.Type) + appendTextNode("*", NodeKind.Type) } else { appendType(projection.type, kind, projection.projectionKind.label) } } - fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") { + fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: NodeKind = NodeKind.Type, prefix: String = "") { if (kotlinType == null) return val classifierDescriptor = kotlinType.constructor.declarationDescriptor @@ -167,17 +175,23 @@ class DocumentationBuilder } val node = DocumentationNode(name, Content.Empty, kind) if (prefix != "") { - node.appendTextNode(prefix, Kind.Modifier) + node.appendTextNode(prefix, NodeKind.Modifier) } if (kotlinType.isMarkedNullable) { - node.appendTextNode("?", Kind.NullabilityModifier) + node.appendTextNode("?", NodeKind.NullabilityModifier) } if (classifierDescriptor != null) { - link(node, classifierDescriptor, - if (classifierDescriptor.isBoringBuiltinClass()) DocumentationReference.Kind.HiddenLink else DocumentationReference.Kind.Link) + val jdkLink = linkResolver.buildJdkLink(classifierDescriptor) + if (jdkLink != null) { + node.append(DocumentationNode(jdkLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) + } + else { + link(node, classifierDescriptor, + if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link) + } } - append(node, DocumentationReference.Kind.Detail) + append(node, RefKind.Detail) node.appendAnnotations(kotlinType) for (typeArgument in kotlinType.arguments) { node.appendProjection(typeArgument) @@ -192,7 +206,7 @@ class DocumentationBuilder val annotationNode = it.build() if (annotationNode != null) { append(annotationNode, - if (annotationNode.isDeprecation()) DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation) + if (annotationNode.isDeprecation()) RefKind.Deprecation else RefKind.Annotation) } } } @@ -201,7 +215,7 @@ class DocumentationBuilder val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach { if (psi.hasModifier(it)) { - appendTextNode(it.value, Kind.Modifier) + appendTextNode(it.value, NodeKind.Modifier) } } } @@ -212,7 +226,7 @@ class DocumentationBuilder appendSourceLink(sourceElement.getPsi(), options.sourceLinks) } - fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind): DocumentationNode? { + fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? { // do not include generated code if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) return null @@ -233,27 +247,28 @@ class DocumentationBuilder (!options.skipDeprecated || !isDeprecated()) } - fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>): List<DocumentationNode> { + fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>, + inheritedLinkKind: RefKind = RefKind.InheritedMember): List<DocumentationNode> { val nodes = descriptors.map { descriptor -> if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull() if (baseDescriptor != null) { - link(this, baseDescriptor, DocumentationReference.Kind.InheritedMember) + link(this, baseDescriptor, inheritedLinkKind) } null } else { val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original - appendChild(descriptorToUse, DocumentationReference.Kind.Member) + appendChild(descriptorToUse, RefKind.Member) } } return nodes.filterNotNull() } - fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) { + fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) { descriptors.forEach { descriptor -> val node = appendChild(descriptor, kind) - node?.addReferenceTo(this, DocumentationReference.Kind.TopLevelPage) + node?.addReferenceTo(this, RefKind.TopLevelPage) } } @@ -268,8 +283,72 @@ class DocumentationBuilder if (options.skipEmptyPackages && declarations.none { it.isDocumented() }) continue logger.info(" package $packageName: ${declarations.count()} declarations") val packageNode = findOrCreatePackageNode(packageName.asString(), packageContent) - packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, declarations) + packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, + declarations, allFqNames) + } + + propagateExtensionFunctionsToSubclasses(fragments) + } + + private fun propagateExtensionFunctionsToSubclasses(fragments: Collection<PackageFragmentDescriptor>) { + val allDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() } + val allClasses = allDescriptors.filterIsInstance<ClassDescriptor>() + val classHierarchy = buildClassHierarchy(allClasses) + + val allExtensionFunctions = allDescriptors + .filterIsInstance<CallableMemberDescriptor>() + .filter { it.extensionReceiverParameter != null } + val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name } + + allExtensionFunctions.forEach { extensionFunction -> + val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name] + ?.filter { fn -> fn.canShadow(extensionFunction) } + ?: emptyList() + + val classDescriptor = extensionFunction.getExtensionClassDescriptor() ?: return@forEach + val subclasses = classHierarchy[classDescriptor] ?: return@forEach + subclasses.forEach { subclass -> + if (subclass.defaultType.isSubtypeOf(extensionFunction.extensionReceiverParameter!!.type) && + possiblyShadowingFunctions.none { subclass.defaultType.isSubtypeOf(it.extensionReceiverParameter!!.type) }) { + refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension) + } + } + } + } + + 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) { + return true + } + if (this is FunctionDescriptor && other is FunctionDescriptor) { + val parameters1 = valueParameters + val parameters2 = other.valueParameters + if (parameters1.size != parameters2.size) { + return false + } + for ((p1, p2) in parameters1 zip parameters2) { + if (p1.type != p2.type) { + return false + } + } + return true + } + return false } fun DeclarationDescriptor.build(): DocumentationNode = when (this) { @@ -284,18 +363,19 @@ class DocumentationBuilder } fun ClassDescriptor.build(): DocumentationNode { - val kind = when (kind) { - ClassKind.OBJECT -> Kind.Object - ClassKind.INTERFACE -> Kind.Interface - ClassKind.ENUM_CLASS -> Kind.Enum - ClassKind.ANNOTATION_CLASS -> Kind.AnnotationClass - ClassKind.ENUM_ENTRY -> Kind.EnumItem - else -> Kind.Class + 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 } val node = nodeForDescriptor(this, kind) node.appendSupertypes(this) if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) { - node.appendInPageChildren(typeConstructor.parameters, DocumentationReference.Kind.Detail) + node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail) val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS) constructors.filter { it.valueParameters.size > 0 } else @@ -305,11 +385,13 @@ class DocumentationBuilder val members = defaultType.memberScope.getContributedDescriptors().filter { it != companionObjectDescriptor } node.appendMembers(members) node.appendMembers(staticScope.getContributedDescriptors()).forEach { - it.appendTextNode("static", Kind.Modifier) + it.appendTextNode("static", NodeKind.Modifier) } val companionObjectDescriptor = companionObjectDescriptor if (companionObjectDescriptor != null) { - node.appendMembers(companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()) + val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors() + val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() } + node.appendMembers(descriptorsToDocument, RefKind.InheritedCompanionObjectMember) } node.appendAnnotations(this) node.appendModifiers(this) @@ -318,9 +400,18 @@ class DocumentationBuilder return node } + 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 } + fun ConstructorDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, Kind.Constructor) - node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail) + val node = nodeForDescriptor(this, NodeKind.Constructor) + node.appendInPageChildren(valueParameters, RefKind.Detail) register(this, node) return node } @@ -339,11 +430,11 @@ class DocumentationBuilder logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}") } - val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectFunction else Kind.Function) + val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function) - node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } - node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail) + node.appendInPageChildren(typeParameters, RefKind.Detail) + extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) } + node.appendInPageChildren(valueParameters, RefKind.Detail) node.appendType(returnType) node.appendAnnotations(this) node.appendModifiers(this) @@ -360,7 +451,7 @@ class DocumentationBuilder fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) { val source = baseClassFunction.original.source.getPsi() if (source != null) { - link(overridingFunction, baseClassFunction, DocumentationReference.Kind.Override) + link(overridingFunction, baseClassFunction, RefKind.Override) } else { baseClassFunction.overriddenDescriptors.forEach { addOverrideLink(it, overridingFunction) @@ -369,15 +460,15 @@ class DocumentationBuilder } fun PropertyDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectProperty else Kind.Property) - node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } + val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property) + node.appendInPageChildren(typeParameters, RefKind.Detail) + extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) } node.appendType(returnType) node.appendAnnotations(this) node.appendModifiers(this) node.appendSourceLink(source) if (isVar) { - node.appendTextNode("var", DocumentationNode.Kind.Modifier) + node.appendTextNode("var", NodeKind.Modifier) } getter?.let { if (!it.isDefault) { @@ -413,21 +504,21 @@ class DocumentationBuilder } fun ValueParameterDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, Kind.Parameter) + 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, Kind.Value) + node.appendTextNode(defaultValueText, NodeKind.Value) } } } node.appendAnnotations(this) node.appendModifiers(this) - if (varargElementType != null && node.details(Kind.Modifier).none { it.name == "vararg" }) { - node.appendTextNode("vararg", Kind.Modifier) + if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) { + node.appendTextNode("vararg", NodeKind.Modifier) } register(this, node) return node @@ -438,25 +529,25 @@ class DocumentationBuilder val name = name.asString() val prefix = variance.label - val node = DocumentationNode(name, doc, DocumentationNode.Kind.TypeParameter) + val node = DocumentationNode(name, doc, NodeKind.TypeParameter) if (prefix != "") { - node.appendTextNode(prefix, Kind.Modifier) + node.appendTextNode(prefix, NodeKind.Modifier) } if (isReified) { - node.appendTextNode("reified", Kind.Modifier) + node.appendTextNode("reified", NodeKind.Modifier) } for (constraint in upperBounds) { if (KotlinBuiltIns.isDefaultBound(constraint)) { continue } - node.appendType(constraint, Kind.UpperBound) + node.appendType(constraint, NodeKind.UpperBound) } for (constraint in lowerBounds) { if (KotlinBuiltIns.isNothing(constraint)) continue - node.appendType(constraint, Kind.LowerBound) + node.appendType(constraint, NodeKind.LowerBound) } return node } @@ -466,11 +557,17 @@ class DocumentationBuilder 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 + } + } link(receiverClass, containingDeclaration, - DocumentationReference.Kind.Extension) + RefKind.Extension) - val node = DocumentationNode(name.asString(), Content.Empty, Kind.Receiver) + val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver) node.appendType(type) return node } @@ -480,24 +577,19 @@ class DocumentationBuilder if (annotationClass == null || ErrorUtils.isError(annotationClass)) { return null } - val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, DocumentationNode.Kind.Annotation) + val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, NodeKind.Annotation) val arguments = allValueArguments.toList().sortedBy { it.first.index } arguments.forEach { val valueNode = it.second.toDocumentationNode() if (valueNode != null) { - val paramNode = DocumentationNode(it.first.name.asString(), Content.Empty, DocumentationNode.Kind.Parameter) - paramNode.append(valueNode, DocumentationReference.Kind.Detail) - node.append(paramNode, DocumentationReference.Kind.Detail) + val paramNode = DocumentationNode(it.first.name.asString(), Content.Empty, NodeKind.Parameter) + paramNode.append(valueNode, RefKind.Detail) + node.append(paramNode, RefKind.Detail) } } return node } - fun CompileTimeConstant<Any?>.build(): DocumentationNode? = when (this) { - is TypedCompileTimeConstant -> constantValue.toDocumentationNode() - else -> null - } - fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value -> when (value) { is String -> @@ -506,7 +598,7 @@ class DocumentationBuilder value.containingDeclaration.name.asString() + "." + value.name.asString() else -> value.toString() }.let { valueString -> - DocumentationNode(valueString, Content.Empty, DocumentationNode.Kind.Value) + DocumentationNode(valueString, Content.Empty, NodeKind.Value) } } } @@ -515,13 +607,14 @@ class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder { override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, packageName: FqName, packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>) { + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName>) { val externalClassNodes = hashMapOf<FqName, DocumentationNode>() declarations.forEach { descriptor -> with(documentationBuilder) { if (descriptor.isDocumented()) { - val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes) - parent.appendChild(descriptor, DocumentationReference.Kind.Member) + val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes, allFqNames) + parent.appendChild(descriptor, RefKind.Member) } } } @@ -545,7 +638,7 @@ class KotlinJavaDocumentationBuilder } else { with(documentationBuilder) { - packageNode.appendChild(descriptor, DocumentationReference.Kind.Member) + packageNode.appendChild(descriptor, RefKind.Member) } } } @@ -555,7 +648,7 @@ class KotlinJavaDocumentationBuilder private fun AnnotationDescriptor.isDocumented(): Boolean { if (source.getPsi() != null && mustBeDocumented()) return true val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString() - return annotationClassName == "kotlin.Extension" + return annotationClassName == "kotlin.ExtensionFunctionType" } fun AnnotationDescriptor.mustBeDocumented(): Boolean { @@ -573,15 +666,16 @@ fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any { } || (this is ConstructorDescriptor && containingDeclaration.isDeprecated()) fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor, - externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode { + externalClassNodes: MutableMap<FqName, DocumentationNode>, + allFqNames: Collection<FqName>): DocumentationNode { if (descriptor is CallableMemberDescriptor) { val extensionClassDescriptor = descriptor.getExtensionClassDescriptor() - if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) && + 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, Kind.ExternalClass) - append(newNode, DocumentationReference.Kind.Member) + val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass) + append(newNode, RefKind.Member) newNode }) } @@ -593,7 +687,11 @@ fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor val extensionReceiver = extensionReceiverParameter if (extensionReceiver != null) { val type = extensionReceiver.type - return type.constructor.declarationDescriptor as? ClassDescriptor + val receiverClass = type.constructor.declarationDescriptor as? ClassDescriptor + if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) { + return receiverClass?.containingDeclaration as? ClassifierDescriptor + } + return receiverClass } return null } @@ -628,10 +726,7 @@ fun CallableMemberDescriptor.parameterSignature(): String { fun KotlinType.signature(): String { val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>" val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString() - if (typeName == "Array" && arguments.size == 1) { - return "Array<" + arguments.first().type.signature() + ">" - } - return typeName + return typeName + arguments.joinToString(prefix = "<", postfix = ">") { it.type.signature() } } fun DeclarationDescriptor.signatureWithSourceLocation(): String { diff --git a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt index 7a1d591c..349a44e7 100644 --- a/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/KotlinAsJavaDocumentationBuilder.kt @@ -19,7 +19,8 @@ class KotlinAsJavaDocumentationBuilder override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, packageName: FqName, packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>) { + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName>) { val project = documentationBuilder.resolutionFacade.project val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName.asString()) if (psiPackage == null) { diff --git a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt index 4aa36b36..a5bb5ee7 100644 --- a/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt +++ b/core/src/main/kotlin/Kotlin/KotlinLanguageService.kt @@ -11,22 +11,22 @@ class KotlinLanguageService : LanguageService { override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode { return content { when (node.kind) { - DocumentationNode.Kind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node) - in DocumentationNode.Kind.classLike -> renderClass(node, renderMode) - - DocumentationNode.Kind.EnumItem, - DocumentationNode.Kind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name) - - DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node, renderMode) - DocumentationNode.Kind.Type, - DocumentationNode.Kind.UpperBound -> renderType(node, renderMode) - - DocumentationNode.Kind.Modifier -> renderModifier(node) - DocumentationNode.Kind.Constructor, - DocumentationNode.Kind.Function, - DocumentationNode.Kind.CompanionObjectFunction -> renderFunction(node, renderMode) - DocumentationNode.Kind.Property, - DocumentationNode.Kind.CompanionObjectProperty -> renderProperty(node, renderMode) + NodeKind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node) + in NodeKind.classLike -> renderClass(node, renderMode) + + NodeKind.EnumItem, + NodeKind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name) + + NodeKind.TypeParameter -> renderTypeParameter(node, renderMode) + NodeKind.Type, + NodeKind.UpperBound -> renderType(node, renderMode) + + NodeKind.Modifier -> renderModifier(node) + NodeKind.Constructor, + NodeKind.Function, + NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode) + NodeKind.Property, + NodeKind.CompanionObjectProperty -> renderProperty(node, renderMode) else -> identifier(node.name) } } @@ -34,7 +34,7 @@ class KotlinLanguageService : LanguageService { override fun renderName(node: DocumentationNode): String { return when (node.kind) { - DocumentationNode.Kind.Constructor -> node.owner!!.name + NodeKind.Constructor -> node.owner!!.name else -> node.name } } @@ -42,10 +42,10 @@ class KotlinLanguageService : LanguageService { override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? { if (nodes.size < 2) return null val receiverKind = nodes.getReceiverKind() ?: return null - val functionWithTypeParameter = nodes.firstOrNull { it.details(DocumentationNode.Kind.TypeParameter).any() } ?: return null + val functionWithTypeParameter = nodes.firstOrNull { it.details(NodeKind.TypeParameter).any() } ?: return null return content { - val typeParameter = functionWithTypeParameter.details(DocumentationNode.Kind.TypeParameter).first() - if (functionWithTypeParameter.kind == DocumentationNode.Kind.Function) { + val typeParameter = functionWithTypeParameter.details(NodeKind.TypeParameter).first() + if (functionWithTypeParameter.kind == NodeKind.Function) { renderFunction(functionWithTypeParameter, RenderMode.SUMMARY, SummarizingMapper(receiverKind, typeParameter.name)) } else { @@ -63,9 +63,9 @@ class KotlinLanguageService : LanguageService { } private fun DocumentationNode.getReceiverQName(): String? { - if (kind != DocumentationNode.Kind.Function && kind != DocumentationNode.Kind.Property) return null - val receiver = details(DocumentationNode.Kind.Receiver).singleOrNull() ?: return null - return receiver.detail(DocumentationNode.Kind.Type).qualifiedNameFromType() + if (kind != NodeKind.Function && kind != NodeKind.Property) return null + val receiver = details(NodeKind.Receiver).singleOrNull() ?: return null + return receiver.detail(NodeKind.Type).qualifiedNameFromType() } companion object { @@ -115,8 +115,8 @@ class KotlinLanguageService : LanguageService { identifier(node.name) } - private fun ContentBlock.renderList(nodes: List<DocumentationNode>, separator: String = ", ", - noWrap: Boolean = false, renderItem: (DocumentationNode) -> Unit) { + private fun <T> ContentBlock.renderList(nodes: List<T>, separator: String = ", ", + noWrap: Boolean = false, renderItem: (T) -> Unit) { if (nodes.none()) return renderItem(nodes.first()) @@ -142,10 +142,10 @@ class KotlinLanguageService : LanguageService { } private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) { - var typeArguments = node.details(DocumentationNode.Kind.Type) + var typeArguments = node.details(NodeKind.Type) if (node.name == "Function${typeArguments.count() - 1}") { // lambda - val isExtension = node.annotations.any { it.name == "Extension" } + val isExtension = node.annotations.any { it.name == "ExtensionFunctionType" } if (isExtension) { renderType(typeArguments.first(), renderMode) symbol(".") @@ -174,7 +174,7 @@ class KotlinLanguageService : LanguageService { } symbol(">") } - val nullabilityModifier = node.details(DocumentationNode.Kind.NullabilityModifier).singleOrNull() + val nullabilityModifier = node.details(NodeKind.NullabilityModifier).singleOrNull() if (nullabilityModifier != null) { symbol(nullabilityModifier.name) } @@ -200,8 +200,8 @@ class KotlinLanguageService : LanguageService { identifier(node.name) - val constraints = node.details(DocumentationNode.Kind.UpperBound) - if (constraints.any()) { + val constraints = node.details(NodeKind.UpperBound) + if (constraints.size == 1) { nbsp() symbol(":") nbsp() @@ -218,9 +218,9 @@ class KotlinLanguageService : LanguageService { identifier(node.name, IdentifierKind.ParameterName) symbol(":") nbsp() - val parameterType = node.detail(DocumentationNode.Kind.Type) + val parameterType = node.detail(NodeKind.Type) renderType(parameterType, renderMode) - val valueNode = node.details(DocumentationNode.Kind.Value).firstOrNull() + val valueNode = node.details(NodeKind.Value).firstOrNull() if (valueNode != null) { nbsp() symbol("=") @@ -230,7 +230,7 @@ class KotlinLanguageService : LanguageService { } private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) { - val typeParameters = node.details(DocumentationNode.Kind.TypeParameter) + val typeParameters = node.details(NodeKind.TypeParameter) if (typeParameters.any()) { symbol("<") renderList(typeParameters) { @@ -240,8 +240,24 @@ class KotlinLanguageService : LanguageService { } } + private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) { + val parametersWithMultipleConstraints = node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 } + val parametersWithConstraints = parametersWithMultipleConstraints + .flatMap { parameter -> parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint } } + if (parametersWithMultipleConstraints.isNotEmpty()) { + keyword(" where ") + renderList(parametersWithConstraints) { + identifier(it.first.name) + nbsp() + symbol(":") + nbsp() + renderType(it.second, renderMode) + } + } + } + private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) { - val supertypes = node.details(DocumentationNode.Kind.Supertype) + val supertypes = node.details(NodeKind.Supertype) if (supertypes.any()) { nbsp() symbol(":") @@ -256,9 +272,9 @@ class KotlinLanguageService : LanguageService { private fun ContentBlock.renderModifiersForNode(node: DocumentationNode, renderMode: RenderMode, nowrap: Boolean = false) { - val modifiers = node.details(DocumentationNode.Kind.Modifier) + val modifiers = node.details(NodeKind.Modifier) for (it in modifiers) { - if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract") + if (node.kind == org.jetbrains.dokka.NodeKind.Interface && it.name == "abstract") continue if (renderMode == RenderMode.SUMMARY && it.name in fullOnlyModifiers) { continue @@ -275,11 +291,11 @@ class KotlinLanguageService : LanguageService { private fun ContentBlock.renderAnnotation(node: DocumentationNode) { identifier("@" + node.name, IdentifierKind.AnnotationName) - val parameters = node.details(DocumentationNode.Kind.Parameter) + val parameters = node.details(NodeKind.Parameter) if (!parameters.isEmpty()) { symbol("(") renderList(parameters) { - text(it.detail(DocumentationNode.Kind.Value).name) + text(it.detail(NodeKind.Value).name) } symbol(")") } @@ -292,18 +308,20 @@ class KotlinLanguageService : LanguageService { } renderModifiersForNode(node, renderMode) when (node.kind) { - DocumentationNode.Kind.Class, - DocumentationNode.Kind.AnnotationClass, - DocumentationNode.Kind.Enum -> keyword("class ") - DocumentationNode.Kind.Interface -> keyword("interface ") - DocumentationNode.Kind.EnumItem -> keyword("enum val ") - DocumentationNode.Kind.Object -> keyword("object ") + NodeKind.Class, + NodeKind.AnnotationClass, + NodeKind.Exception, + NodeKind.Enum -> keyword("class ") + NodeKind.Interface -> keyword("interface ") + NodeKind.EnumItem -> keyword("enum val ") + NodeKind.Object -> keyword("object ") else -> throw IllegalArgumentException("Node $node is not a class-like object") } identifierOrDeprecated(node) renderTypeParametersForNode(node, renderMode) renderSupertypesForNode(node, renderMode) + renderExtraTypeParameterConstraints(node, renderMode) } private fun ContentBlock.renderFunction(node: DocumentationNode, @@ -314,23 +332,23 @@ class KotlinLanguageService : LanguageService { } renderModifiersForNode(node, renderMode) when (node.kind) { - DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name) - DocumentationNode.Kind.Function, - DocumentationNode.Kind.CompanionObjectFunction -> keyword("fun ") + NodeKind.Constructor -> identifier(node.owner!!.name) + NodeKind.Function, + NodeKind.CompanionObjectFunction -> keyword("fun ") else -> throw IllegalArgumentException("Node $node is not a function-like object") } renderTypeParametersForNode(node, renderMode) - if (node.details(DocumentationNode.Kind.TypeParameter).any()) { + if (node.details(NodeKind.TypeParameter).any()) { text(" ") } renderReceiver(node, renderMode, signatureMapper) - if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor) + if (node.kind != org.jetbrains.dokka.NodeKind.Constructor) identifierOrDeprecated(node) symbol("(") - val parameters = node.details(DocumentationNode.Kind.Parameter) + val parameters = node.details(NodeKind.Parameter) renderList(parameters) { indentedSoftLineBreak() renderParameter(it, renderMode) @@ -341,32 +359,33 @@ class KotlinLanguageService : LanguageService { } symbol(")") symbol(": ") - renderType(node.detail(DocumentationNode.Kind.Type), renderMode) + renderType(node.detail(NodeKind.Type), renderMode) } else { symbol(")") } + renderExtraTypeParameterConstraints(node, renderMode) } private fun ContentBlock.renderReceiver(node: DocumentationNode, renderMode: RenderMode, signatureMapper: SignatureMapper?) { - val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull() + val receiver = node.details(NodeKind.Receiver).singleOrNull() if (receiver != null) { if (signatureMapper != null) { signatureMapper.renderReceiver(receiver, this) } else { - renderType(receiver.detail(DocumentationNode.Kind.Type), renderMode) + renderType(receiver.detail(NodeKind.Type), renderMode) } symbol(".") } } private fun needReturnType(node: DocumentationNode) = when(node.kind) { - DocumentationNode.Kind.Constructor -> false + NodeKind.Constructor -> false else -> !node.isUnitReturnType() } fun DocumentationNode.isUnitReturnType(): Boolean = - detail(DocumentationNode.Kind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit" + detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit" private fun ContentBlock.renderProperty(node: DocumentationNode, renderMode: RenderMode, @@ -376,12 +395,12 @@ class KotlinLanguageService : LanguageService { } renderModifiersForNode(node, renderMode) when (node.kind) { - DocumentationNode.Kind.Property, - DocumentationNode.Kind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ") + NodeKind.Property, + NodeKind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ") else -> throw IllegalArgumentException("Node $node is not a property") } renderTypeParametersForNode(node, renderMode) - if (node.details(DocumentationNode.Kind.TypeParameter).any()) { + if (node.details(NodeKind.TypeParameter).any()) { text(" ") } @@ -389,11 +408,12 @@ class KotlinLanguageService : LanguageService { identifierOrDeprecated(node) symbol(": ") - renderType(node.detail(DocumentationNode.Kind.Type), renderMode) + renderType(node.detail(NodeKind.Type), renderMode) + renderExtraTypeParameterConstraints(node, renderMode) } fun DocumentationNode.getPropertyKeyword() = - if (details(DocumentationNode.Kind.Modifier).any { it.name == "var" }) "var" else "val" + if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val" fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) { if (node.deprecation != null) { diff --git a/core/src/main/kotlin/Languages/JavaLanguageService.kt b/core/src/main/kotlin/Languages/JavaLanguageService.kt index 7e40beff..d6f9ade5 100644 --- a/core/src/main/kotlin/Languages/JavaLanguageService.kt +++ b/core/src/main/kotlin/Languages/JavaLanguageService.kt @@ -1,31 +1,30 @@ package org.jetbrains.dokka -import org.jetbrains.dokka.DocumentationNode.Kind import org.jetbrains.dokka.LanguageService.RenderMode /** * Implements [LanguageService] and provides rendering of symbols in Java language */ -public class JavaLanguageService : LanguageService { +class JavaLanguageService : LanguageService { override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode { return ContentText(when (node.kind) { - Kind.Package -> renderPackage(node) - in Kind.classLike -> renderClass(node) + NodeKind.Package -> renderPackage(node) + in NodeKind.classLike -> renderClass(node) - Kind.TypeParameter -> renderTypeParameter(node) - Kind.Type, - Kind.UpperBound -> renderType(node) + NodeKind.TypeParameter -> renderTypeParameter(node) + NodeKind.Type, + NodeKind.UpperBound -> renderType(node) - Kind.Constructor, - Kind.Function -> renderFunction(node) - Kind.Property -> renderProperty(node) + NodeKind.Constructor, + NodeKind.Function -> renderFunction(node) + NodeKind.Property -> renderProperty(node) else -> "${node.kind}: ${node.name}" }) } override fun renderName(node: DocumentationNode): String { return when (node.kind) { - Kind.Constructor -> node.owner!!.name + NodeKind.Constructor -> node.owner!!.name else -> node.name } } @@ -44,19 +43,19 @@ public class JavaLanguageService : LanguageService { } } - public fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.name) { - "Array" -> node.details(Kind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?: DocumentationNode("Object", node.content, DocumentationNode.Kind.ExternalClass) - "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, DocumentationNode.Kind.Type) + fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.name) { + "Array" -> node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?: DocumentationNode("Object", node.content, NodeKind.ExternalClass) + "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type) else -> null } - public fun getArrayDimension(node: DocumentationNode): Int = when (node.name) { - "Array" -> 1 + (node.details(DocumentationNode.Kind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0) + fun getArrayDimension(node: DocumentationNode): Int = when (node.name) { + "Array" -> 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0) "IntArray", "LongArray", "ShortArray", "ByteArray", "CharArray", "DoubleArray", "FloatArray", "BooleanArray" -> 1 else -> 0 } - public fun renderType(node: DocumentationNode): String { + fun renderType(node: DocumentationNode): String { return when (node.name) { "Unit" -> "void" "Int" -> "int" @@ -71,7 +70,7 @@ public class JavaLanguageService : LanguageService { } private fun renderTypeParameter(node: DocumentationNode): String { - val constraints = node.details(Kind.UpperBound) + val constraints = node.details(NodeKind.UpperBound) return if (constraints.none()) node.name else { @@ -80,12 +79,12 @@ public class JavaLanguageService : LanguageService { } private fun renderParameter(node: DocumentationNode): String { - return "${renderType(node.detail(Kind.Type))} ${node.name}" + return "${renderType(node.detail(NodeKind.Type))} ${node.name}" } private fun renderTypeParametersForNode(node: DocumentationNode): String { return StringBuilder().apply { - val typeParameters = node.details(Kind.TypeParameter) + val typeParameters = node.details(NodeKind.TypeParameter) if (typeParameters.any()) { append("<") append(typeParameters.map { renderTypeParameter(it) }.joinToString()) @@ -95,7 +94,7 @@ public class JavaLanguageService : LanguageService { } private fun renderModifiersForNode(node: DocumentationNode): String { - val modifiers = node.details(Kind.Modifier).map { renderModifier(it) }.filter { it != "" } + val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" } if (modifiers.none()) return "" return modifiers.joinToString(" ", postfix = " ") @@ -104,11 +103,11 @@ public class JavaLanguageService : LanguageService { private fun renderClass(node: DocumentationNode): String { return StringBuilder().apply { when (node.kind) { - Kind.Class -> append("class ") - Kind.Interface -> append("interface ") - Kind.Enum -> append("enum ") - Kind.EnumItem -> append("enum value ") - Kind.Object -> append("class ") + NodeKind.Class -> append("class ") + NodeKind.Interface -> append("interface ") + NodeKind.Enum -> append("enum ") + NodeKind.EnumItem -> append("enum value ") + NodeKind.Object -> append("class ") else -> throw IllegalArgumentException("Node $node is not a class-like object") } @@ -120,22 +119,22 @@ public class JavaLanguageService : LanguageService { private fun renderFunction(node: DocumentationNode): String { return StringBuilder().apply { when (node.kind) { - Kind.Constructor -> append(node.owner?.name) - Kind.Function -> { + NodeKind.Constructor -> append(node.owner?.name) + NodeKind.Function -> { append(renderTypeParametersForNode(node)) - append(renderType(node.detail(Kind.Type))) + append(renderType(node.detail(NodeKind.Type))) append(" ") append(node.name) } else -> throw IllegalArgumentException("Node $node is not a function-like object") } - val receiver = node.details(Kind.Receiver).singleOrNull() + val receiver = node.details(NodeKind.Receiver).singleOrNull() append("(") if (receiver != null) - (listOf(receiver) + node.details(Kind.Parameter)).map { renderParameter(it) }.joinTo(this) + (listOf(receiver) + node.details(NodeKind.Parameter)).map { renderParameter(it) }.joinTo(this) else - node.details(Kind.Parameter).map { renderParameter(it) }.joinTo(this) + node.details(NodeKind.Parameter).map { renderParameter(it) }.joinTo(this) append(")") }.toString() @@ -144,19 +143,19 @@ public class JavaLanguageService : LanguageService { private fun renderProperty(node: DocumentationNode): String { return StringBuilder().apply { when (node.kind) { - Kind.Property -> append("val ") + NodeKind.Property -> append("val ") else -> throw IllegalArgumentException("Node $node is not a property") } append(renderTypeParametersForNode(node)) - val receiver = node.details(Kind.Receiver).singleOrNull() + val receiver = node.details(NodeKind.Receiver).singleOrNull() if (receiver != null) { - append(renderType(receiver.detail(Kind.Type))) + append(renderType(receiver.detail(NodeKind.Type))) append(".") } append(node.name) append(": ") - append(renderType(node.detail(Kind.Type))) + append(renderType(node.detail(NodeKind.Type))) }.toString() } }
\ No newline at end of file diff --git a/core/src/main/kotlin/Locations/FoldersLocationService.kt b/core/src/main/kotlin/Locations/FoldersLocationService.kt index 89b34ed1..83e1cf6a 100644 --- a/core/src/main/kotlin/Locations/FoldersLocationService.kt +++ b/core/src/main/kotlin/Locations/FoldersLocationService.kt @@ -4,8 +4,9 @@ import com.google.inject.Inject import com.google.inject.name.Named import java.io.File -public fun FoldersLocationService(root: String): FoldersLocationService = FoldersLocationService(File(root), "") -public class FoldersLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService { +class FoldersLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService { + constructor(root: String): this(File(root), "") + override val root: Location get() = FileLocation(rootFile) diff --git a/core/src/main/kotlin/Locations/LocationService.kt b/core/src/main/kotlin/Locations/LocationService.kt index 80bc0236..63c236ed 100644 --- a/core/src/main/kotlin/Locations/LocationService.kt +++ b/core/src/main/kotlin/Locations/LocationService.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka import java.io.File -public interface Location { +interface Location { val path: String get fun relativePathTo(other: Location, anchor: String? = null): String } @@ -15,7 +15,7 @@ public interface Location { * $file: [File] for this location * $path: [String] representing path of this location */ -public data class FileLocation(val file: File): Location { +data class FileLocation(val file: File): Location { override val path : String get() = file.path @@ -41,7 +41,7 @@ public data class FileLocation(val file: File): Location { * * [SingleFolderLocationService] – all documentation is generated into single folder using fully qualified names * for file names. */ -public interface LocationService { +interface LocationService { fun withExtension(newExtension: String) = this fun location(node: DocumentationNode): Location = location(node.path.map { it.name }, node.members.any()) @@ -56,7 +56,7 @@ public interface LocationService { } -public interface FileLocationService: LocationService { +interface FileLocationService: LocationService { override fun withExtension(newExtension: String): FileLocationService = this override fun location(node: DocumentationNode): FileLocation = location(node.path.map { it.name }, node.members.any()) @@ -64,7 +64,7 @@ public interface FileLocationService: LocationService { } -public fun identifierToFilename(path: String): String { +fun identifierToFilename(path: String): String { val escaped = path.replace('<', '-').replace('>', '-') val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() } return if (lowercase == "index") "--index--" else lowercase diff --git a/core/src/main/kotlin/Locations/SingleFolderLocationService.kt b/core/src/main/kotlin/Locations/SingleFolderLocationService.kt index e313ac28..1b4fdc28 100644 --- a/core/src/main/kotlin/Locations/SingleFolderLocationService.kt +++ b/core/src/main/kotlin/Locations/SingleFolderLocationService.kt @@ -4,8 +4,9 @@ import com.google.inject.Inject import com.google.inject.name.Named import java.io.File -public fun SingleFolderLocationService(root: String): SingleFolderLocationService = SingleFolderLocationService(File(root), "") -public class SingleFolderLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService { +class SingleFolderLocationService @Inject constructor(@Named("outputDir") val rootFile: File, val extension: String) : FileLocationService { + constructor(root: String): this(File(root), "") + override fun withExtension(newExtension: String): FileLocationService = SingleFolderLocationService(rootFile, newExtension) diff --git a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt b/core/src/main/kotlin/Markdown/MarkdownProcessor.kt index 99caddc4..46b72c03 100644 --- a/core/src/main/kotlin/Markdown/MarkdownProcessor.kt +++ b/core/src/main/kotlin/Markdown/MarkdownProcessor.kt @@ -24,7 +24,7 @@ fun MarkdownNode.visit(action: (MarkdownNode, () -> Unit) -> Unit) { } } -public fun MarkdownNode.toTestString(): String { +fun MarkdownNode.toTestString(): String { val sb = StringBuilder() var level = 0 visit { node, visitChildren -> diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt index 6556b09e..4c69f6cb 100644 --- a/core/src/main/kotlin/Model/Content.kt +++ b/core/src/main/kotlin/Model/Content.kt @@ -1,14 +1,14 @@ package org.jetbrains.dokka -public interface ContentNode { +interface ContentNode { val textLength: Int } -public object ContentEmpty : ContentNode { +object ContentEmpty : ContentNode { override val textLength: Int get() = 0 } -public open class ContentBlock() : ContentNode { +open class ContentBlock() : ContentNode { val children = arrayListOf<ContentNode>() fun append(node: ContentNode) { @@ -35,58 +35,58 @@ enum class IdentifierKind { Other } -public data class ContentText(val text: String) : ContentNode { +data class ContentText(val text: String) : ContentNode { override val textLength: Int get() = text.length } -public data class ContentKeyword(val text: String) : ContentNode { +data class ContentKeyword(val text: String) : ContentNode { override val textLength: Int get() = text.length } -public data class ContentIdentifier(val text: String, val kind: IdentifierKind = IdentifierKind.Other) : ContentNode { +data class ContentIdentifier(val text: String, val kind: IdentifierKind = IdentifierKind.Other) : ContentNode { override val textLength: Int get() = text.length } -public data class ContentSymbol(val text: String) : ContentNode { +data class ContentSymbol(val text: String) : ContentNode { override val textLength: Int get() = text.length } -public data class ContentEntity(val text: String) : ContentNode { +data class ContentEntity(val text: String) : ContentNode { override val textLength: Int get() = text.length } -public object ContentNonBreakingSpace: ContentNode { +object ContentNonBreakingSpace: ContentNode { override val textLength: Int get() = 1 } -public object ContentSoftLineBreak: ContentNode { +object ContentSoftLineBreak: ContentNode { override val textLength: Int get() = 0 } -public object ContentIndentedSoftLineBreak: ContentNode { +object ContentIndentedSoftLineBreak: ContentNode { override val textLength: Int get() = 0 } -public class ContentParagraph() : ContentBlock() -public class ContentEmphasis() : ContentBlock() -public class ContentStrong() : ContentBlock() -public class ContentStrikethrough() : ContentBlock() -public class ContentCode() : ContentBlock() -public class ContentBlockCode(val language: String = "") : ContentBlock() +class ContentParagraph() : ContentBlock() +class ContentEmphasis() : ContentBlock() +class ContentStrong() : ContentBlock() +class ContentStrikethrough() : ContentBlock() +class ContentCode() : ContentBlock() +class ContentBlockCode(val language: String = "") : ContentBlock() -public abstract class ContentNodeLink() : ContentBlock() { +abstract class ContentNodeLink() : ContentBlock() { abstract val node: DocumentationNode? } -public class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() { +class ContentNodeDirectLink(override val node: DocumentationNode): ContentNodeLink() { override fun equals(other: Any?): Boolean = super.equals(other) && other is ContentNodeDirectLink && node.name == other.node.name @@ -94,7 +94,7 @@ public class ContentNodeDirectLink(override val node: DocumentationNode): Conten children.hashCode() * 31 + node.name.hashCode() } -public class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() { +class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> DocumentationNode?): ContentNodeLink() { override val node: DocumentationNode? get() = lazyNode() override fun equals(other: Any?): Boolean = @@ -104,7 +104,7 @@ public class ContentNodeLazyLink(val linkText: String, val lazyNode: () -> Docum children.hashCode() * 31 + linkText.hashCode() } -public class ContentExternalLink(val href : String) : ContentBlock() { +class ContentExternalLink(val href : String) : ContentBlock() { override fun equals(other: Any?): Boolean = super.equals(other) && other is ContentExternalLink && href == other.href @@ -112,13 +112,13 @@ public class ContentExternalLink(val href : String) : ContentBlock() { children.hashCode() * 31 + href.hashCode() } -public class ContentUnorderedList() : ContentBlock() -public class ContentOrderedList() : ContentBlock() -public class ContentListItem() : ContentBlock() +class ContentUnorderedList() : ContentBlock() +class ContentOrderedList() : ContentBlock() +class ContentListItem() : ContentBlock() -public class ContentHeading(val level: Int) : ContentBlock() +class ContentHeading(val level: Int) : ContentBlock() -public class ContentSection(public val tag: String, public val subjectName: String?) : ContentBlock() { +class ContentSection(val tag: String, val subjectName: String?) : ContentBlock() { override fun equals(other: Any?): Boolean = super.equals(other) && other is ContentSection && tag == other.tag && subjectName == other.subjectName @@ -126,7 +126,7 @@ public class ContentSection(public val tag: String, public val subjectName: Stri children.hashCode() * 31 * 31 + tag.hashCode() * 31 + (subjectName?.hashCode() ?: 0) } -public object ContentTags { +object ContentTags { val Description = "Description" val SeeAlso = "See Also" } @@ -158,15 +158,19 @@ fun ContentBlock.code(body: ContentBlock.() -> Unit) { } fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) { - val block = ContentNodeDirectLink(to) + val block = if (to.kind == NodeKind.ExternalLink) + ContentExternalLink(to.name) + else + ContentNodeDirectLink(to) + block.body() append(block) } -public open class Content(): ContentBlock() { - public open val sections: List<ContentSection> get() = emptyList() - public open val summary: ContentNode get() = ContentEmpty - public open val description: ContentNode get() = ContentEmpty +open class Content(): ContentBlock() { + open val sections: List<ContentSection> get() = emptyList() + open val summary: ContentNode get() = ContentEmpty + open val description: ContentNode get() = ContentEmpty fun findSectionByTag(tag: String): ContentSection? = sections.firstOrNull { tag.equals(it.tag, ignoreCase = true) } @@ -182,9 +186,9 @@ public open class Content(): ContentBlock() { } } -public open class MutableContent() : Content() { +open class MutableContent() : Content() { private val sectionList = arrayListOf<ContentSection>() - public override val sections: List<ContentSection> + override val sections: List<ContentSection> get() = sectionList fun addSection(tag: String?, subjectName: String?): ContentSection { @@ -193,9 +197,9 @@ public open class MutableContent() : Content() { return section } - public override val summary: ContentNode get() = children.firstOrNull() ?: ContentEmpty + override val summary: ContentNode get() = children.firstOrNull() ?: ContentEmpty - public override val description: ContentNode by lazy { + override val description: ContentNode by lazy { val descriptionNodes = children.drop(1) if (descriptionNodes.isEmpty()) { ContentEmpty diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt index 52881f65..3cedb8e6 100644 --- a/core/src/main/kotlin/Model/DocumentationNode.kt +++ b/core/src/main/kotlin/Model/DocumentationNode.kt @@ -2,127 +2,132 @@ package org.jetbrains.dokka import java.util.* -public open class DocumentationNode(val name: String, - content: Content, - val kind: DocumentationNode.Kind) { +enum class NodeKind { + Unknown, + + Package, + Class, + Interface, + Enum, + AnnotationClass, + Exception, + EnumItem, + Object, + + Constructor, + Function, + Property, + Field, + + CompanionObjectProperty, + CompanionObjectFunction, + + Parameter, + Receiver, + TypeParameter, + Type, + Supertype, + UpperBound, + LowerBound, + + Modifier, + NullabilityModifier, + + Module, + + ExternalClass, + Annotation, + + Value, + + SourceUrl, + SourcePosition, + + ExternalLink, + + /** + * A note which is rendered once on a page documenting a group of overloaded functions. + * Needs to be generated equally on all overloads. + */ + OverloadGroupNote; + + companion object { + val classLike = setOf(Class, Interface, Enum, AnnotationClass, Exception, Object) + } +} + +open class DocumentationNode(val name: String, + content: Content, + val kind: NodeKind) { private val references = LinkedHashSet<DocumentationReference>() var content: Content = content private set - public val summary: ContentNode get() = content.summary - - public val owner: DocumentationNode? - get() = references(DocumentationReference.Kind.Owner).singleOrNull()?.to - public val details: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Detail).map { it.to } - public val members: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Member).map { it.to } - public val inheritedMembers: List<DocumentationNode> - get() = references(DocumentationReference.Kind.InheritedMember).map { it.to } - public val extensions: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Extension).map { it.to } - public val inheritors: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Inheritor).map { it.to } - public val overrides: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Override).map { it.to } - public val links: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Link).map { it.to } - public val hiddenLinks: List<DocumentationNode> - get() = references(DocumentationReference.Kind.HiddenLink).map { it.to } - public val annotations: List<DocumentationNode> - get() = references(DocumentationReference.Kind.Annotation).map { it.to } - public val deprecation: DocumentationNode? - get() = references(DocumentationReference.Kind.Deprecation).singleOrNull()?.to + val summary: ContentNode get() = content.summary + + 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 inheritedMembers: List<DocumentationNode> + get() = references(RefKind.InheritedMember).map { it.to } + 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 // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice - public fun addReferenceTo(to: DocumentationNode, kind: DocumentationReference.Kind) { + fun addReferenceTo(to: DocumentationNode, kind: RefKind) { references.add(DocumentationReference(this, to, kind)) } - public fun addAllReferencesFrom(other: DocumentationNode) { + fun addAllReferencesFrom(other: DocumentationNode) { references.addAll(other.references) } - public fun updateContent(body: MutableContent.() -> Unit) { + fun updateContent(body: MutableContent.() -> Unit) { if (content !is MutableContent) { content = MutableContent() } (content as MutableContent).body() } - public fun details(kind: DocumentationNode.Kind): List<DocumentationNode> = details.filter { it.kind == kind } - public fun members(kind: DocumentationNode.Kind): List<DocumentationNode> = members.filter { it.kind == kind } - public fun inheritedMembers(kind: DocumentationNode.Kind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind } - public fun links(kind: DocumentationNode.Kind): List<DocumentationNode> = links.filter { it.kind == kind } + fun details(kind: NodeKind): List<DocumentationNode> = details.filter { it.kind == kind } + fun members(kind: NodeKind): List<DocumentationNode> = members.filter { it.kind == kind } + fun inheritedMembers(kind: NodeKind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind } + fun inheritedCompanionObjectMembers(kind: NodeKind): List<DocumentationNode> = inheritedCompanionObjectMembers.filter { it.kind == kind } + fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind } - public fun detail(kind: DocumentationNode.Kind): DocumentationNode = details.filter { it.kind == kind }.single() - public fun member(kind: DocumentationNode.Kind): DocumentationNode = members.filter { it.kind == kind }.single() - public fun link(kind: DocumentationNode.Kind): DocumentationNode = links.filter { it.kind == kind }.single() + fun detail(kind: NodeKind): DocumentationNode = details.filter { it.kind == kind }.single() + fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single() + fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single() - public fun references(kind: DocumentationReference.Kind): List<DocumentationReference> = references.filter { it.kind == kind } - public fun allReferences(): Set<DocumentationReference> = references + fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind } + fun allReferences(): Set<DocumentationReference> = references - public override fun toString(): String { + override fun toString(): String { return "$kind:$name" } - - public enum class Kind { - Unknown, - - Package, - Class, - Interface, - Enum, - AnnotationClass, - EnumItem, - Object, - - Constructor, - Function, - Property, - Field, - - CompanionObjectProperty, - CompanionObjectFunction, - - Parameter, - Receiver, - TypeParameter, - Type, - Supertype, - UpperBound, - LowerBound, - Exception, - - Modifier, - NullabilityModifier, - - Module, - - ExternalClass, - Annotation, - - Value, - - SourceUrl, - SourcePosition, - - /** - * A note which is rendered once on a page documenting a group of overloaded functions. - * Needs to be generated equally on all overloads. - */ - OverloadGroupNote; - - companion object { - val classLike = setOf(Class, Interface, Enum, AnnotationClass, Object) - } - } } -public class DocumentationModule(name: String, content: Content = Content.Empty) - : DocumentationNode(name, content, DocumentationNode.Kind.Module) { +class DocumentationModule(name: String, content: Content = Content.Empty) + : DocumentationNode(name, content, NodeKind.Module) { } val DocumentationNode.path: List<DocumentationNode> @@ -132,30 +137,30 @@ val DocumentationNode.path: List<DocumentationNode> } fun DocumentationNode.findOrCreatePackageNode(packageName: String, packageContent: Map<String, Content>): DocumentationNode { - val existingNode = members(DocumentationNode.Kind.Package).firstOrNull { it.name == packageName } + val existingNode = members(NodeKind.Package).firstOrNull { it.name == packageName } if (existingNode != null) { return existingNode } val newNode = DocumentationNode(packageName, packageContent.getOrElse(packageName) { Content.Empty }, - DocumentationNode.Kind.Package) - append(newNode, DocumentationReference.Kind.Member) + NodeKind.Package) + append(newNode, RefKind.Member) return newNode } -fun DocumentationNode.append(child: DocumentationNode, kind: DocumentationReference.Kind) { +fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) { addReferenceTo(child, kind) when (kind) { - DocumentationReference.Kind.Detail -> child.addReferenceTo(this, DocumentationReference.Kind.Owner) - DocumentationReference.Kind.Member -> child.addReferenceTo(this, DocumentationReference.Kind.Owner) - DocumentationReference.Kind.Owner -> child.addReferenceTo(this, DocumentationReference.Kind.Member) + RefKind.Detail -> child.addReferenceTo(this, RefKind.Owner) + RefKind.Member -> child.addReferenceTo(this, RefKind.Owner) + RefKind.Owner -> child.addReferenceTo(this, RefKind.Member) else -> { /* Do not add any links back for other types */ } } } fun DocumentationNode.appendTextNode(text: String, - kind: DocumentationNode.Kind, - refKind: DocumentationReference.Kind = DocumentationReference.Kind.Detail) { + kind: NodeKind, + refKind: RefKind = RefKind.Detail) { append(DocumentationNode(text, Content.Empty, kind), refKind) } diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt index 898c92d7..0b40e83a 100644 --- a/core/src/main/kotlin/Model/DocumentationReference.kt +++ b/core/src/main/kotlin/Model/DocumentationReference.kt @@ -2,27 +2,29 @@ package org.jetbrains.dokka import com.google.inject.Singleton -public data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: DocumentationReference.Kind) { - public enum class Kind { - Owner, - Member, - InheritedMember, - Detail, - Link, - HiddenLink, - Extension, - Inheritor, - Superclass, - Override, - Annotation, - Deprecation, - TopLevelPage - } +enum class RefKind { + Owner, + Member, + InheritedMember, + InheritedCompanionObjectMember, + Detail, + Link, + HiddenLink, + Extension, + Inheritor, + Superclass, + Override, + Annotation, + Deprecation, + TopLevelPage +} + +data class DocumentationReference(val from: DocumentationNode, val to: DocumentationNode, val kind: RefKind) { } class PendingDocumentationReference(val lazyNodeFrom: () -> DocumentationNode?, val lazyNodeTo: () -> DocumentationNode?, - val kind: DocumentationReference.Kind) { + val kind: RefKind) { fun resolve() { val fromNode = lazyNodeFrom() val toNode = lazyNodeTo() @@ -41,15 +43,15 @@ class NodeReferenceGraph() { nodeMap.put(signature, node) } - fun link(fromNode: DocumentationNode, toSignature: String, kind: DocumentationReference.Kind) { + fun link(fromNode: DocumentationNode, toSignature: String, kind: RefKind) { references.add(PendingDocumentationReference({ -> fromNode}, { -> nodeMap[toSignature]}, kind)) } - fun link(fromSignature: String, toNode: DocumentationNode, kind: DocumentationReference.Kind) { + fun link(fromSignature: String, toNode: DocumentationNode, kind: RefKind) { references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> toNode}, kind)) } - fun link(fromSignature: String, toSignature: String, kind: DocumentationReference.Kind) { + fun link(fromSignature: String, toSignature: String, kind: RefKind) { references.add(PendingDocumentationReference({ -> nodeMap[fromSignature]}, { -> nodeMap[toSignature]}, kind)) } diff --git a/core/src/main/kotlin/Model/PackageDocs.kt b/core/src/main/kotlin/Model/PackageDocs.kt index 044c73d8..5ebf2119 100644 --- a/core/src/main/kotlin/Model/PackageDocs.kt +++ b/core/src/main/kotlin/Model/PackageDocs.kt @@ -8,13 +8,13 @@ import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor import java.io.File @Singleton -public class PackageDocs +class PackageDocs @Inject constructor(val linkResolver: DeclarationLinkResolver?, val logger: DokkaLogger) { - public val moduleContent: MutableContent = MutableContent() + val moduleContent: MutableContent = MutableContent() private val _packageContent: MutableMap<String, MutableContent> = hashMapOf() - public val packageContent: Map<String, Content> + val packageContent: Map<String, Content> get() = _packageContent fun parse(fileName: String, linkResolveContext: LazyPackageDescriptor?) { diff --git a/core/src/main/kotlin/Model/SourceLinks.kt b/core/src/main/kotlin/Model/SourceLinks.kt index 956bfe4b..99bb8f60 100644 --- a/core/src/main/kotlin/Model/SourceLinks.kt +++ b/core/src/main/kotlin/Model/SourceLinks.kt @@ -1,10 +1,10 @@ package org.jetbrains.dokka -import com.intellij.psi.PsiElement -import java.io.File import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import org.jetbrains.kotlin.psi.psiUtil.startOffset +import java.io.File class SourceLinkDefinition(val path: String, val url: String, val lineSuffix: String?) @@ -22,12 +22,12 @@ fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<Sourc url += linkDef.lineSuffix + line.toString() } } - append(DocumentationNode(url, Content.Empty, DocumentationNode.Kind.SourceUrl), - DocumentationReference.Kind.Detail); + append(DocumentationNode(url, Content.Empty, NodeKind.SourceUrl), + RefKind.Detail); } if (target != null) { - append(DocumentationNode(target.sourcePosition(), Content.Empty, DocumentationNode.Kind.SourcePosition), DocumentationReference.Kind.Detail) + append(DocumentationNode(target.sourcePosition(), Content.Empty, NodeKind.SourcePosition), RefKind.Detail) } } diff --git a/core/src/main/kotlin/Utilities/Html.kt b/core/src/main/kotlin/Utilities/Html.kt index ce3a1982..a5a93d9e 100644 --- a/core/src/main/kotlin/Utilities/Html.kt +++ b/core/src/main/kotlin/Utilities/Html.kt @@ -5,4 +5,4 @@ package org.jetbrains.dokka * Replaces symbols reserved in HTML with their respective entities. * Replaces & with &, < with < and > with > */ -public fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">") +fun String.htmlEscape(): String = replace("&", "&").replace("<", "<").replace(">", ">") diff --git a/core/src/main/kotlin/Utilities/ServiceLocator.kt b/core/src/main/kotlin/Utilities/ServiceLocator.kt index 7a5aff79..6c29d1cd 100644 --- a/core/src/main/kotlin/Utilities/ServiceLocator.kt +++ b/core/src/main/kotlin/Utilities/ServiceLocator.kt @@ -9,8 +9,8 @@ data class ServiceDescriptor(val name: String, val category: String, val descrip class ServiceLookupException(message: String) : Exception(message) -public object ServiceLocator { - public fun <T : Any> lookup(clazz: Class<T>, category: String, implementationName: String): T { +object ServiceLocator { + fun <T : Any> lookup(clazz: Class<T>, category: String, implementationName: String): T { val descriptor = lookupDescriptor(category, implementationName) val loadedClass = javaClass.classLoader.loadClass(descriptor.className) val constructor = loadedClass.constructors @@ -66,7 +66,7 @@ public object ServiceLocator { } } -public inline fun <reified T : Any> ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName) +inline fun <reified T : Any> ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName) private val ZipEntry.fileName: String get() = name.substringAfterLast("/", name) diff --git a/core/src/main/kotlin/ant/dokka.kt b/core/src/main/kotlin/ant/dokka.kt index d78980f8..713bd193 100644 --- a/core/src/main/kotlin/ant/dokka.kt +++ b/core/src/main/kotlin/ant/dokka.kt @@ -1,12 +1,12 @@ package org.jetbrains.dokka.ant +import org.apache.tools.ant.BuildException +import org.apache.tools.ant.Project import org.apache.tools.ant.Task import org.apache.tools.ant.types.Path import org.apache.tools.ant.types.Reference -import org.apache.tools.ant.BuildException -import org.apache.tools.ant.Project -import org.jetbrains.dokka.DokkaLogger import org.jetbrains.dokka.DokkaGenerator +import org.jetbrains.dokka.DokkaLogger import org.jetbrains.dokka.SourceLinkDefinition import java.io.File @@ -19,48 +19,48 @@ class AntLogger(val task: Task): DokkaLogger { class AntSourceLinkDefinition(var path: String? = null, var url: String? = null, var lineSuffix: String? = null) class DokkaAntTask(): Task() { - public var moduleName: String? = null - public var outputDir: String? = null - public var outputFormat: String = "html" + var moduleName: String? = null + var outputDir: String? = null + var outputFormat: String = "html" - public var skipDeprecated: Boolean = false + var skipDeprecated: Boolean = false - public val compileClasspath: Path = Path(getProject()) - public val sourcePath: Path = Path(getProject()) - public val samplesPath: Path = Path(getProject()) - public val includesPath: Path = Path(getProject()) + val compileClasspath: Path = Path(getProject()) + val sourcePath: Path = Path(getProject()) + val samplesPath: Path = Path(getProject()) + val includesPath: Path = Path(getProject()) - public val antSourceLinks: MutableList<AntSourceLinkDefinition> = arrayListOf() + val antSourceLinks: MutableList<AntSourceLinkDefinition> = arrayListOf() - public fun setClasspath(classpath: Path) { + fun setClasspath(classpath: Path) { compileClasspath.append(classpath) } - public fun setClasspathRef(ref: Reference) { + fun setClasspathRef(ref: Reference) { compileClasspath.createPath().refid = ref } - public fun setSrc(src: Path) { + fun setSrc(src: Path) { sourcePath.append(src) } - public fun setSrcRef(ref: Reference) { + fun setSrcRef(ref: Reference) { sourcePath.createPath().refid = ref } - public fun setSamples(samples: Path) { + fun setSamples(samples: Path) { samplesPath.append(samples) } - public fun setSamplesRef(ref: Reference) { + fun setSamplesRef(ref: Reference) { samplesPath.createPath().refid = ref } - public fun setInclude(include: Path) { + fun setInclude(include: Path) { includesPath.append(include) } - public fun createSourceLink(): AntSourceLinkDefinition { + fun createSourceLink(): AntSourceLinkDefinition { val def = AntSourceLinkDefinition() antSourceLinks.add(def) return def diff --git a/core/src/main/kotlin/javadoc/docbase.kt b/core/src/main/kotlin/javadoc/docbase.kt index a0caca94..25733464 100644 --- a/core/src/main/kotlin/javadoc/docbase.kt +++ b/core/src/main/kotlin/javadoc/docbase.kt @@ -34,17 +34,17 @@ open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : override fun getRawCommentText(): String = rawCommentText_ ?: "" override fun isError(): Boolean = false - override fun isException(): Boolean = node.kind == DocumentationNode.Kind.Exception - override fun isEnumConstant(): Boolean = node.kind == DocumentationNode.Kind.EnumItem - override fun isEnum(): Boolean = node.kind == DocumentationNode.Kind.Enum - override fun isMethod(): Boolean = node.kind == DocumentationNode.Kind.Function - override fun isInterface(): Boolean = node.kind == DocumentationNode.Kind.Interface - override fun isField(): Boolean = node.kind == DocumentationNode.Kind.Field - override fun isClass(): Boolean = node.kind == DocumentationNode.Kind.Class - override fun isAnnotationType(): Boolean = node.kind == DocumentationNode.Kind.AnnotationClass - override fun isConstructor(): Boolean = node.kind == DocumentationNode.Kind.Constructor - override fun isOrdinaryClass(): Boolean = node.kind == DocumentationNode.Kind.Class - override fun isAnnotationTypeElement(): Boolean = node.kind == DocumentationNode.Kind.Annotation + override fun isException(): Boolean = node.kind == NodeKind.Exception + override fun isEnumConstant(): Boolean = node.kind == NodeKind.EnumItem + override fun isEnum(): Boolean = node.kind == NodeKind.Enum + override fun isMethod(): Boolean = node.kind == NodeKind.Function + override fun isInterface(): Boolean = node.kind == NodeKind.Interface + override fun isField(): Boolean = node.kind == NodeKind.Field + override fun isClass(): Boolean = node.kind == NodeKind.Class + override fun isAnnotationType(): Boolean = node.kind == NodeKind.AnnotationClass + override fun isConstructor(): Boolean = node.kind == NodeKind.Constructor + override fun isOrdinaryClass(): Boolean = node.kind == NodeKind.Class + override fun isAnnotationTypeElement(): Boolean = node.kind == NodeKind.Annotation override fun compareTo(other: Any?): Int = when (other) { !is DocumentationNodeAdapter -> 1 @@ -54,7 +54,7 @@ open class DocumentationNodeBareAdapter(override val node: DocumentationNode) : override fun equals(other: Any?): Boolean = node.qualifiedName() == (other as? DocumentationNodeAdapter)?.node?.qualifiedName() override fun hashCode(): Int = node.name.hashCode() - override fun isIncluded(): Boolean = node.kind != DocumentationNode.Kind.ExternalClass + override fun isIncluded(): Boolean = node.kind != NodeKind.ExternalClass } @@ -89,7 +89,7 @@ private fun <T> nodeAnnotations(self: T): List<AnnotationDescAdapter> where T : = self.node.annotations.map { AnnotationDescAdapter(self.module, it) } private fun DocumentationNode.hasAnnotation(klass: KClass<*>) = klass.qualifiedName in annotations.map { it.qualifiedName() } -private fun DocumentationNode.hasModifier(name: String) = details(DocumentationNode.Kind.Modifier).any { it.name == name } +private fun DocumentationNode.hasModifier(name: String) = details(NodeKind.Modifier).any { it.name == name } class PackageAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), PackageDoc { @@ -99,12 +99,12 @@ class PackageAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : Docum allClasses.get(className)?.let { ClassDocumentationNodeAdapter(module, it) } override fun annotationTypes(): Array<out AnnotationTypeDoc> = emptyArray() - override fun annotations(): Array<out AnnotationDesc> = node.members(DocumentationNode.Kind.AnnotationClass).map { AnnotationDescAdapter(module, it) }.toTypedArray() - override fun exceptions(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Exception).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() - override fun ordinaryClasses(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() - override fun interfaces(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Interface).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun annotations(): Array<out AnnotationDesc> = node.members(NodeKind.AnnotationClass).map { AnnotationDescAdapter(module, it) }.toTypedArray() + override fun exceptions(): Array<out ClassDoc> = node.members(NodeKind.Exception).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun ordinaryClasses(): Array<out ClassDoc> = node.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun interfaces(): Array<out ClassDoc> = node.members(NodeKind.Interface).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() override fun errors(): Array<out ClassDoc> = emptyArray() - override fun enums(): Array<out ClassDoc> = node.members(DocumentationNode.Kind.Enum).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun enums(): Array<out ClassDoc> = node.members(NodeKind.Enum).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() override fun allClasses(filter: Boolean): Array<out ClassDoc> = allClasses.values.map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() override fun allClasses(): Array<out ClassDoc> = allClasses(true) @@ -126,7 +126,7 @@ class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) override fun isPackagePrivate(): Boolean = false override fun isStatic(): Boolean = node.hasModifier("static") override fun modifierSpecifier(): Int = Modifier.PUBLIC + if (isStatic) Modifier.STATIC else 0 - override fun qualifiedName(): String? = if (node.kind == DocumentationNode.Kind.Type) node.qualifiedNameFromType() else node.qualifiedName() + override fun qualifiedName(): String? = if (node.kind == NodeKind.Type) node.qualifiedNameFromType() else node.qualifiedName() override fun annotations(): Array<out AnnotationDesc>? = nodeAnnotations(this).toTypedArray() override fun modifiers(): String? = "public ${if (isStatic) "static" else ""}".trim() override fun isProtected(): Boolean = false @@ -134,13 +134,13 @@ class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) override fun isFinal(): Boolean = node.hasModifier("final") override fun containingPackage(): PackageDoc? { - if (node.kind == DocumentationNode.Kind.Type) { + if (node.kind == NodeKind.Type) { return null } var owner: DocumentationNode? = node while (owner != null) { - if (owner.kind == DocumentationNode.Kind.Package) { + if (owner.kind == NodeKind.Package) { return PackageAdapter(module, owner) } owner = owner.owner @@ -150,16 +150,16 @@ class ProgramElementAdapter(module: ModuleNodeAdapter, node: DocumentationNode) } override fun containingClass(): ClassDoc? { - if (node.kind == DocumentationNode.Kind.Type) { + if (node.kind == NodeKind.Type) { return null } var owner = node.owner while (owner != null) { when (owner.kind) { - DocumentationNode.Kind.Class, - DocumentationNode.Kind.Interface, - DocumentationNode.Kind.Enum -> return ClassDocumentationNodeAdapter(module, owner) + NodeKind.Class, + NodeKind.Interface, + NodeKind.Enum -> return ClassDocumentationNodeAdapter(module, owner) else -> owner = owner.owner } } @@ -184,9 +184,9 @@ open class TypeAdapter(override val module: ModuleNodeAdapter, override val node override fun asClassDoc(): ClassDoc? = if (isPrimitive) null else elementType?.asClassDoc() ?: when (node.kind) { - in DocumentationNode.Kind.classLike, - DocumentationNode.Kind.ExternalClass, - DocumentationNode.Kind.Exception -> module.classNamed(qualifiedTypeName()) ?: ClassDocumentationNodeAdapter(module, node) + in NodeKind.classLike, + NodeKind.ExternalClass, + NodeKind.Exception -> module.classNamed(qualifiedTypeName()) ?: ClassDocumentationNodeAdapter(module, node) else -> when { node.links.isNotEmpty() -> TypeAdapter(module, node.links.first()).asClassDoc() @@ -194,12 +194,12 @@ open class TypeAdapter(override val module: ModuleNodeAdapter, override val node } } - override fun asTypeVariable(): TypeVariable? = if (node.kind == DocumentationNode.Kind.TypeParameter) TypeVariableAdapter(module, node) else null + override fun asTypeVariable(): TypeVariable? = if (node.kind == NodeKind.TypeParameter) TypeVariableAdapter(module, node) else null override fun asParameterizedType(): ParameterizedType? = - if (node.details(DocumentationNode.Kind.Type).isNotEmpty()) ParameterizedTypeAdapter(module, node) + if (node.details(NodeKind.Type).isNotEmpty()) ParameterizedTypeAdapter(module, node) else null // TODO it should ignore dimensions - override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = if (node.kind == DocumentationNode.Kind.AnnotationClass) AnnotationTypeDocAdapter(module, node) else null + override fun asAnnotationTypeDoc(): AnnotationTypeDoc? = if (node.kind == NodeKind.AnnotationClass) AnnotationTypeDocAdapter(module, node) else null override fun asAnnotatedType(): AnnotatedType? = if (node.annotations.isNotEmpty()) AnnotatedTypeAdapter(module, node) else null override fun getElementType(): Type? = javaLanguageService.getArrayElementType(node)?.let { et -> TypeAdapter(module, et) } override fun asWildcardType(): WildcardType? = null @@ -215,26 +215,26 @@ class AnnotatedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : } class WildcardTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), WildcardType { - override fun extendsBounds(): Array<out Type> = node.details(DocumentationNode.Kind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray() - override fun superBounds(): Array<out Type> = node.details(DocumentationNode.Kind.LowerBound).map { TypeAdapter(module, it) }.toTypedArray() + override fun extendsBounds(): Array<out Type> = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray() + override fun superBounds(): Array<out Type> = node.details(NodeKind.LowerBound).map { TypeAdapter(module, it) }.toTypedArray() } class TypeVariableAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), TypeVariable { override fun owner(): ProgramElementDoc = node.owner!!.let<DocumentationNode, ProgramElementDoc> { owner -> when (owner.kind) { - DocumentationNode.Kind.Function, - DocumentationNode.Kind.Constructor -> ExecutableMemberAdapter(module, owner) + NodeKind.Function, + NodeKind.Constructor -> ExecutableMemberAdapter(module, owner) - DocumentationNode.Kind.Class, - DocumentationNode.Kind.Interface, - DocumentationNode.Kind.Enum -> ClassDocumentationNodeAdapter(module, owner) + NodeKind.Class, + NodeKind.Interface, + NodeKind.Enum -> ClassDocumentationNodeAdapter(module, owner) else -> ProgramElementAdapter(module, node.owner!!) } } - override fun bounds(): Array<out Type>? = node.details(DocumentationNode.Kind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray() - override fun annotations(): Array<out AnnotationDesc>? = node.members(DocumentationNode.Kind.Annotation).map { AnnotationDescAdapter(module, it) }.toTypedArray() + override fun bounds(): Array<out Type>? = node.details(NodeKind.UpperBound).map { TypeAdapter(module, it) }.toTypedArray() + override fun annotations(): Array<out AnnotationDesc>? = node.members(NodeKind.Annotation).map { AnnotationDescAdapter(module, it) }.toTypedArray() override fun qualifiedTypeName(): String = node.name override fun simpleTypeName(): String = node.name @@ -247,32 +247,32 @@ class TypeVariableAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : } class ParameterizedTypeAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : TypeAdapter(module, node), ParameterizedType { - override fun typeArguments(): Array<out Type> = node.details(DocumentationNode.Kind.Type).map { TypeVariableAdapter(module, it) }.toTypedArray() + override fun typeArguments(): Array<out Type> = node.details(NodeKind.Type).map { TypeVariableAdapter(module, it) }.toTypedArray() override fun superclassType(): Type? = node.lookupSuperClasses(module) - .firstOrNull { it.kind == DocumentationNode.Kind.Class || it.kind == DocumentationNode.Kind.ExternalClass } + .firstOrNull { it.kind == NodeKind.Class || it.kind == NodeKind.ExternalClass } ?.let { ClassDocumentationNodeAdapter(module, it) } override fun interfaceTypes(): Array<out Type> = node.lookupSuperClasses(module) - .filter { it.kind == DocumentationNode.Kind.Interface } + .filter { it.kind == NodeKind.Interface } .map { ClassDocumentationNodeAdapter(module, it) } .toTypedArray() override fun containingType(): Type? = when (node.owner?.kind) { - DocumentationNode.Kind.Package -> null - DocumentationNode.Kind.Class, - DocumentationNode.Kind.Interface, - DocumentationNode.Kind.Object, - DocumentationNode.Kind.Enum -> ClassDocumentationNodeAdapter(module, node.owner!!) + NodeKind.Package -> null + NodeKind.Class, + NodeKind.Interface, + NodeKind.Object, + NodeKind.Enum -> ClassDocumentationNodeAdapter(module, node.owner!!) else -> null } } class ParameterAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), Parameter { - override fun typeName(): String? = JavaLanguageService().renderType(node.detail(DocumentationNode.Kind.Type)) - override fun type(): Type? = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type)) + override fun typeName(): String? = JavaLanguageService().renderType(node.detail(NodeKind.Type)) + override fun type(): Type? = TypeAdapter(module, node.detail(NodeKind.Type)) override fun annotations(): Array<out AnnotationDesc> = nodeAnnotations(this).toTypedArray() } @@ -288,10 +288,10 @@ class ReceiverParameterAdapter(module: ModuleNodeAdapter, val receiverType: Docu } } -fun classOf(fqName: String, kind: DocumentationNode.Kind = DocumentationNode.Kind.Class) = DocumentationNode(fqName.substringAfterLast(".", fqName), Content.Empty, kind).let { node -> +fun classOf(fqName: String, kind: NodeKind = NodeKind.Class) = DocumentationNode(fqName.substringAfterLast(".", fqName), Content.Empty, kind).let { node -> val pkg = fqName.substringBeforeLast(".", "") if (pkg.isNotEmpty()) { - node.append(DocumentationNode(pkg, Content.Empty, DocumentationNode.Kind.Package), DocumentationReference.Kind.Owner) + node.append(DocumentationNode(pkg, Content.Empty, NodeKind.Package), RefKind.Owner) } node @@ -308,37 +308,37 @@ open class ExecutableMemberAdapter(module: ModuleNodeAdapter, node: Documentatio .filter { it.tag == "Exceptions" } .map { it.subjectName } .filterNotNull() - .map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it, DocumentationNode.Kind.Exception))) } + .map { ThrowsTagAdapter(this, ClassDocumentationNodeAdapter(module, classOf(it, NodeKind.Exception))) } .toTypedArray() - override fun isVarArgs(): Boolean = node.details(DocumentationNode.Kind.Parameter).any { false } // TODO + override fun isVarArgs(): Boolean = node.details(NodeKind.Parameter).any { false } // TODO override fun isSynchronized(): Boolean = node.annotations.any { it.name == "synchronized" } - override fun paramTags(): Array<out ParamTag> = node.details(DocumentationNode.Kind.Parameter) + override fun paramTags(): Array<out ParamTag> = node.details(NodeKind.Parameter) .filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() } .map { ParamTagAdapter(module, this, it.name, false, it.content.children) } .toTypedArray() override fun thrownExceptionTypes(): Array<out Type> = emptyArray() override fun receiverType(): Type? = receiverNode()?.let { receiver -> TypeAdapter(module, receiver) } - override fun flatSignature(): String = node.details(DocumentationNode.Kind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") - override fun signature(): String = node.details(DocumentationNode.Kind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") // TODO it should be FQ types + override fun flatSignature(): String = node.details(NodeKind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") + override fun signature(): String = node.details(NodeKind.Parameter).map { JavaLanguageService().renderType(it) }.joinToString(", ", "(", ")") // TODO it should be FQ types override fun parameters(): Array<out Parameter> = ((receiverNode()?.let { receiver -> listOf<Parameter>(ReceiverParameterAdapter(module, receiver, this)) } ?: emptyList()) - + node.details(DocumentationNode.Kind.Parameter).map { ParameterAdapter(module, it) } + + node.details(NodeKind.Parameter).map { ParameterAdapter(module, it) } ).toTypedArray() - override fun typeParameters(): Array<out TypeVariable> = node.details(DocumentationNode.Kind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray() + override fun typeParameters(): Array<out TypeVariable> = node.details(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray() - override fun typeParamTags(): Array<out ParamTag> = node.details(DocumentationNode.Kind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map { + override fun typeParamTags(): Array<out ParamTag> = node.details(NodeKind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map { ParamTagAdapter(module, this, it.name, true, it.content.children) }.toTypedArray() - private fun receiverNode() = node.details(DocumentationNode.Kind.Receiver).let { receivers -> + private fun receiverNode() = node.details(NodeKind.Receiver).let { receivers -> when { - receivers.isNotEmpty() -> receivers.single().detail(DocumentationNode.Kind.Type) + receivers.isNotEmpty() -> receivers.single().detail(NodeKind.Type) else -> null } } @@ -360,16 +360,16 @@ class MethodAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : Docume override fun isDefault(): Boolean = false - override fun returnType(): Type = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type)) + override fun returnType(): Type = TypeAdapter(module, node.detail(NodeKind.Type)) } class FieldAdapter(module: ModuleNodeAdapter, node: DocumentationNode) : DocumentationNodeAdapter(module, node), ProgramElementDoc by ProgramElementAdapter(module, node), FieldDoc { override fun isSynthetic(): Boolean = false - override fun constantValueExpression(): String? = node.details(DocumentationNode.Kind.Value).firstOrNull()?.let { it.name } + override fun constantValueExpression(): String? = node.details(NodeKind.Value).firstOrNull()?.let { it.name } override fun constantValue(): Any? = constantValueExpression() - override fun type(): Type = TypeAdapter(module, node.detail(DocumentationNode.Kind.Type)) + override fun type(): Type = TypeAdapter(module, node.detail(NodeKind.Type)) override fun isTransient(): Boolean = node.hasAnnotation(Transient::class) override fun serialFieldTags(): Array<out SerialFieldTag> = emptyArray() @@ -384,48 +384,48 @@ open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNod override fun name(): String { val parent = classNode.owner - if (parent?.kind in DocumentationNode.Kind.classLike) { + if (parent?.kind in NodeKind.classLike) { return parent!!.name + "." + classNode.name } return classNode.name } - override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(DocumentationNode.Kind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray() + override fun constructors(filter: Boolean): Array<out ConstructorDoc> = classNode.members(NodeKind.Constructor).map { ConstructorAdapter(module, it) }.toTypedArray() override fun constructors(): Array<out ConstructorDoc> = constructors(true) override fun importedPackages(): Array<out PackageDoc> = emptyArray() override fun importedClasses(): Array<out ClassDoc>? = emptyArray() - override fun typeParameters(): Array<out TypeVariable> = classNode.details(DocumentationNode.Kind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray() - override fun asTypeVariable(): TypeVariable? = if (classNode.kind == DocumentationNode.Kind.Class) TypeVariableAdapter(module, classNode) else null + override fun typeParameters(): Array<out TypeVariable> = classNode.details(NodeKind.TypeParameter).map { TypeVariableAdapter(module, it) }.toTypedArray() + override fun asTypeVariable(): TypeVariable? = if (classNode.kind == NodeKind.Class) TypeVariableAdapter(module, classNode) else null override fun isExternalizable(): Boolean = interfaces().any { it.qualifiedName() == "java.io.Externalizable" } override fun definesSerializableFields(): Boolean = false - override fun methods(filter: Boolean): Array<out MethodDoc> = classNode.members(DocumentationNode.Kind.Function).map { MethodAdapter(module, it) }.toTypedArray() // TODO include get/set methods + override fun methods(filter: Boolean): Array<out MethodDoc> = classNode.members(NodeKind.Function).map { MethodAdapter(module, it) }.toTypedArray() // TODO include get/set methods override fun methods(): Array<out MethodDoc> = methods(true) - override fun enumConstants(): Array<out FieldDoc>? = classNode.members(DocumentationNode.Kind.EnumItem).map { FieldAdapter(module, it) }.toTypedArray() - override fun isAbstract(): Boolean = classNode.details(DocumentationNode.Kind.Modifier).any { it.name == "abstract" } + override fun enumConstants(): Array<out FieldDoc>? = classNode.members(NodeKind.EnumItem).map { FieldAdapter(module, it) }.toTypedArray() + override fun isAbstract(): Boolean = classNode.details(NodeKind.Modifier).any { it.name == "abstract" } override fun interfaceTypes(): Array<out Type> = classNode.lookupSuperClasses(module) - .filter { it.kind == DocumentationNode.Kind.Interface } + .filter { it.kind == NodeKind.Interface } .map { ClassDocumentationNodeAdapter(module, it) } .toTypedArray() override fun interfaces(): Array<out ClassDoc> = classNode.lookupSuperClasses(module) - .filter { it.kind == DocumentationNode.Kind.Interface } + .filter { it.kind == NodeKind.Interface } .map { ClassDocumentationNodeAdapter(module, it) } .toTypedArray() - override fun typeParamTags(): Array<out ParamTag> = (classNode.details(DocumentationNode.Kind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map { + override fun typeParamTags(): Array<out ParamTag> = (classNode.details(NodeKind.TypeParameter).filter { it.content.summary !is ContentEmpty || it.content.description !is ContentEmpty || it.content.sections.isNotEmpty() }.map { ParamTagAdapter(module, this, it.name, true, it.content.children) } + classNode.content.sections.filter { it.subjectName in typeParameters().map { it.simpleTypeName() } }.map { ParamTagAdapter(module, this, it.subjectName ?: "?", true, it.children) }).toTypedArray() override fun fields(): Array<out FieldDoc> = fields(true) - override fun fields(filter: Boolean): Array<out FieldDoc> = classNode.members(DocumentationNode.Kind.Field).map { FieldAdapter(module, it) }.toTypedArray() + override fun fields(filter: Boolean): Array<out FieldDoc> = classNode.members(NodeKind.Field).map { FieldAdapter(module, it) }.toTypedArray() override fun findClass(className: String?): ClassDoc? = null // TODO !!! override fun serializableFields(): Array<out FieldDoc> = emptyArray() - override fun superclassType(): Type? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == DocumentationNode.Kind.Class }?.let { ClassDocumentationNodeAdapter(module, it) } + override fun superclassType(): Type? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == NodeKind.Class }?.let { ClassDocumentationNodeAdapter(module, it) } override fun serializationMethods(): Array<out MethodDoc> = emptyArray() // TODO - override fun superclass(): ClassDoc? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == DocumentationNode.Kind.Class }?.let { ClassDocumentationNodeAdapter(module, it) } + override fun superclass(): ClassDoc? = classNode.lookupSuperClasses(module).singleOrNull { it.kind == NodeKind.Class }?.let { ClassDocumentationNodeAdapter(module, it) } override fun isSerializable(): Boolean = false // TODO override fun subclassOf(cd: ClassDoc?): Boolean { if (cd == null) { @@ -445,18 +445,18 @@ open class ClassDocumentationNodeAdapter(module: ModuleNodeAdapter, val classNod } visitedTypes.add(fqName) - types.addAll(type.details(DocumentationNode.Kind.Supertype).filter { it.qualifiedName() !in visitedTypes }) + types.addAll(type.details(NodeKind.Supertype).filter { it.qualifiedName() !in visitedTypes }) } return false } - override fun innerClasses(): Array<out ClassDoc> = classNode.members(DocumentationNode.Kind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() + override fun innerClasses(): Array<out ClassDoc> = classNode.members(NodeKind.Class).map { ClassDocumentationNodeAdapter(module, it) }.toTypedArray() override fun innerClasses(filter: Boolean): Array<out ClassDoc> = innerClasses() } fun DocumentationNode.lookupSuperClasses(module: ModuleNodeAdapter) = - details(DocumentationNode.Kind.Supertype) + details(NodeKind.Supertype) .map { it.links.firstOrNull() } .map { module.allTypes[it?.qualifiedName()] } .filterNotNull() @@ -465,7 +465,7 @@ fun List<DocumentationNode>.collectAllTypesRecursively(): Map<String, Documentat val result = hashMapOf<String, DocumentationNode>() fun DocumentationNode.collectTypesRecursively() { - val classLikeMembers = DocumentationNode.Kind.classLike.flatMap { members(it) } + val classLikeMembers = NodeKind.classLike.flatMap { members(it) } classLikeMembers.forEach { result.put(it.qualifiedName(), it) it.collectTypesRecursively() @@ -477,8 +477,8 @@ fun List<DocumentationNode>.collectAllTypesRecursively(): Map<String, Documentat } class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorReporter, val outputPath: String) : DocumentationNodeBareAdapter(module), DocErrorReporter by reporter, RootDoc { - val allPackages = module.members(DocumentationNode.Kind.Package).toMapBy { it.name } - val allTypes = module.members(DocumentationNode.Kind.Package).collectAllTypesRecursively() + val allPackages = module.members(NodeKind.Package).toMapBy { it.name } + val allTypes = module.members(NodeKind.Package).collectAllTypesRecursively() override fun packageNamed(name: String?): PackageDoc? = allPackages[name]?.let { PackageAdapter(this, it) } @@ -492,7 +492,7 @@ class ModuleNodeAdapter(val module: DocumentationModule, val reporter: DocErrorR arrayOf("-keywords") ) - override fun specifiedPackages(): Array<out PackageDoc>? = module.members(DocumentationNode.Kind.Package).map { PackageAdapter(this, it) }.toTypedArray() + override fun specifiedPackages(): Array<out PackageDoc>? = module.members(NodeKind.Package).map { PackageAdapter(this, it) }.toTypedArray() override fun classNamed(qualifiedName: String?): ClassDoc? = allTypes[qualifiedName]?.let { ClassDocumentationNodeAdapter(this, it) } diff --git a/core/src/main/kotlin/javadoc/source-position.kt b/core/src/main/kotlin/javadoc/source-position.kt index 0e4c6e3c..6125f968 100644 --- a/core/src/main/kotlin/javadoc/source-position.kt +++ b/core/src/main/kotlin/javadoc/source-position.kt @@ -2,12 +2,13 @@ package org.jetbrains.dokka.javadoc import com.sun.javadoc.SourcePosition import org.jetbrains.dokka.DocumentationNode +import org.jetbrains.dokka.NodeKind import java.io.File class SourcePositionAdapter(val docNode: DocumentationNode) : SourcePosition { private val sourcePositionParts: List<String> by lazy { - docNode.details(DocumentationNode.Kind.SourcePosition).firstOrNull()?.name?.split(":") ?: emptyList() + docNode.details(NodeKind.SourcePosition).firstOrNull()?.name?.split(":") ?: emptyList() } override fun file(): File? = if (sourcePositionParts.isEmpty()) null else File(sourcePositionParts[0]) diff --git a/core/src/main/kotlin/javadoc/tags.kt b/core/src/main/kotlin/javadoc/tags.kt index 5872dbaa..aab5ecf1 100644 --- a/core/src/main/kotlin/javadoc/tags.kt +++ b/core/src/main/kotlin/javadoc/tags.kt @@ -176,9 +176,9 @@ private fun buildInlineTags(module: ModuleNodeAdapter, holder: Doc, node: Conten is ContentNodeLink -> { val target = node.node when (target?.kind) { - DocumentationNode.Kind.Function -> result.add(SeeMethodTagAdapter(holder, MethodAdapter(module, node.node!!), node)) + NodeKind.Function -> result.add(SeeMethodTagAdapter(holder, MethodAdapter(module, node.node!!), node)) - in DocumentationNode.Kind.classLike -> result.add(SeeClassTagAdapter(holder, ClassDocumentationNodeAdapter(module, node.node!!), node)) + in NodeKind.classLike -> result.add(SeeClassTagAdapter(holder, ClassDocumentationNodeAdapter(module, node.node!!), node)) else -> buildInlineTags(module, holder, node.children, result) } diff --git a/core/src/main/kotlin/main.kt b/core/src/main/kotlin/main.kt index c0a24caf..91f30bb0 100644 --- a/core/src/main/kotlin/main.kt +++ b/core/src/main/kotlin/main.kt @@ -27,38 +27,38 @@ import kotlin.system.measureTimeMillis class DokkaArguments { @set:Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)") @ValueDescription("<path>") - public var src: String = "" + var src: String = "" @set:Argument(value = "srcLink", description = "Mapping between a source directory and a Web site for browsing the code") @ValueDescription("<path>=<url>[#lineSuffix]") - public var srcLink: String = "" + var srcLink: String = "" @set:Argument(value = "include", description = "Markdown files to load (allows many paths separated by the system path separator)") @ValueDescription("<path>") - public var include: String = "" + var include: String = "" @set:Argument(value = "samples", description = "Source root for samples") @ValueDescription("<path>") - public var samples: String = "" + var samples: String = "" @set:Argument(value = "output", description = "Output directory path") @ValueDescription("<path>") - public var outputDir: String = "out/doc/" + var outputDir: String = "out/doc/" @set:Argument(value = "format", description = "Output format (text, html, markdown, jekyll, kotlin-website)") @ValueDescription("<name>") - public var outputFormat: String = "html" + var outputFormat: String = "html" @set:Argument(value = "module", description = "Name of the documentation module") @ValueDescription("<name>") - public var moduleName: String = "" + var moduleName: String = "" @set:Argument(value = "classpath", description = "Classpath for symbol resolution") @ValueDescription("<path>") - public var classpath: String = "" + var classpath: String = "" @set:Argument(value = "nodeprecated", description = "Exclude deprecated members from documentation") - public var nodeprecated: Boolean = false + var nodeprecated: Boolean = false } @@ -69,7 +69,7 @@ private fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it }) } -public fun main(args: Array<String>) { +fun main(args: Array<String>) { val arguments = DokkaArguments() val freeArgs: List<String> = Args.parse(arguments, args) ?: listOf() val sources = if (arguments.src.isNotEmpty()) arguments.src.split(File.pathSeparatorChar).toList() + freeArgs else freeArgs |