aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2015-11-04 13:56:13 +0100
committerDmitry Jemerov <yole@jetbrains.com>2015-11-04 13:56:13 +0100
commit21dcc4a472f88dd3ce1a1e7d8406905552896d3c (patch)
tree90dcf22298be4741cb05d38a579cb41256d94db4 /src
parentfb25c1eaf41ae314d19d6cda55446a2ab6b63715 (diff)
downloaddokka-21dcc4a472f88dd3ce1a1e7d8406905552896d3c.tar.gz
dokka-21dcc4a472f88dd3ce1a1e7d8406905552896d3c.tar.bz2
dokka-21dcc4a472f88dd3ce1a1e7d8406905552896d3c.zip
extract JavadocParser to a separate file; extract DeclarationLinkResolver out of DocumentationBuilder
Diffstat (limited to 'src')
-rw-r--r--src/Java/JavaPsiDocumentationBuilder.kt170
-rw-r--r--src/Java/JavadocParser.kt170
-rw-r--r--src/Kotlin/DeclarationLinkResolver.kt44
-rw-r--r--src/Kotlin/DocumentationBuilder.kt146
-rw-r--r--src/Model/PackageDocs.kt6
-rw-r--r--src/main.kt5
6 files changed, 278 insertions, 263 deletions
diff --git a/src/Java/JavaPsiDocumentationBuilder.kt b/src/Java/JavaPsiDocumentationBuilder.kt
index bdc6a368..b1e3167d 100644
--- a/src/Java/JavaPsiDocumentationBuilder.kt
+++ b/src/Java/JavaPsiDocumentationBuilder.kt
@@ -1,177 +1,9 @@
package org.jetbrains.dokka
import com.intellij.psi.*
-import com.intellij.psi.javadoc.PsiDocTag
-import com.intellij.psi.javadoc.PsiDocTagValue
-import com.intellij.psi.javadoc.PsiDocToken
-import com.intellij.psi.javadoc.PsiInlineDocTag
import org.jetbrains.dokka.DocumentationNode.Kind
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Node
-import org.jsoup.nodes.TextNode
-
-data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) {
- companion object {
- val Empty = JavadocParseResult(Content.Empty, null)
- }
-}
-
-interface JavaDocumentationParser {
- fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
-}
-
-class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentationParser {
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val docComment = (element as? PsiDocCommentOwner)?.docComment
- if (docComment == null) return JavadocParseResult.Empty
- val result = MutableContent()
- var deprecatedContent: Content? = null
- val para = ContentParagraph()
- result.append(para)
- para.convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() })
- docComment.tags.forEach { tag ->
- when(tag.name) {
- "see" -> result.convertSeeTag(tag)
- "deprecated" -> {
- deprecatedContent = Content()
- deprecatedContent!!.convertJavadocElements(tag.contentElements())
- }
- else -> {
- val subjectName = tag.getSubjectName()
- val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
-
- section.convertJavadocElements(tag.contentElements())
- }
- }
- }
- return JavadocParseResult(result, deprecatedContent)
- }
-
- private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
- val tagValueElements = children
- .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
- .dropWhile { it is PsiWhiteSpace }
- .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
- return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
- }
-
- private fun ContentBlock.convertJavadocElements(elements: Iterable<PsiElement>) {
- val htmlBuilder = StringBuilder()
- elements.forEach {
- if (it is PsiInlineDocTag) {
- htmlBuilder.append(convertInlineDocTag(it))
- } else {
- htmlBuilder.append(it.text)
- }
- }
- val doc = Jsoup.parse(htmlBuilder.toString().trimStart())
- doc.body().childNodes().forEach {
- convertHtmlNode(it)
- }
- }
-
- private fun ContentBlock.convertHtmlNode(node: Node) {
- if (node is TextNode) {
- append(ContentText(node.text()))
- } else if (node is Element) {
- val childBlock = createBlock(node)
- node.childNodes().forEach {
- childBlock.convertHtmlNode(it)
- }
- append(childBlock)
- }
- }
-
- private fun createBlock(element: Element): ContentBlock = when(element.tagName()) {
- "p" -> ContentParagraph()
- "b", "strong" -> ContentStrong()
- "i", "em" -> ContentEmphasis()
- "s", "del" -> ContentStrikethrough()
- "code" -> ContentCode()
- "pre" -> ContentBlockCode()
- "ul" -> ContentUnorderedList()
- "ol" -> ContentOrderedList()
- "li" -> ContentListItem()
- "a" -> createLink(element)
- else -> ContentBlock()
- }
-
- private fun createLink(element: Element): ContentBlock {
- val docref = element.attr("docref")
- if (docref != null) {
- return ContentNodeLazyLink(docref, { -> refGraph.lookup(docref)})
- }
- val href = element.attr("href")
- if (href != null) {
- return ContentExternalLink(href)
- } else {
- return ContentBlock()
- }
- }
-
- private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
- val linkElement = tag.linkElement()
- if (linkElement == null) {
- return
- }
- val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
- val linkSignature = resolveLink(linkElement)
- val text = ContentText(linkElement.text)
- if (linkSignature != null) {
- val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookup(linkSignature)})
- linkNode.append(text)
- seeSection.append(linkNode)
- } else {
- seeSection.append(text)
- }
- }
-
- private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.name) {
- "link", "linkplain" -> {
- val valueElement = tag.linkElement()
- val linkSignature = resolveLink(valueElement)
- if (linkSignature != null) {
- val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val link = "<a docref=\"$linkSignature\">${labelText.htmlEscape()}</a>"
- if (tag.name == "link") "<code>$link</code>" else link
- }
- else if (valueElement != null) {
- valueElement.text
- } else {
- ""
- }
- }
- "code", "literal" -> {
- val text = StringBuilder()
- tag.dataElements.forEach { text.append(it.text) }
- val escaped = text.toString().trimStart().htmlEscape()
- if (tag.name == "code") "<code>$escaped</code>" else escaped
- }
- else -> tag.text
- }
-
- private fun PsiDocTag.linkElement(): PsiElement? =
- valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
-
- private fun resolveLink(valueElement: PsiElement?): String? {
- val target = valueElement?.reference?.resolve()
- if (target != null) {
- return getSignature(target)
- }
- return null
- }
-
- fun PsiDocTag.getSubjectName(): String? {
- if (name == "param" || name == "throws" || name == "exception") {
- return valueElement?.text
- }
- return null
- }
-}
-
-private fun getSignature(element: PsiElement?) = when(element) {
+fun getSignature(element: PsiElement?) = when(element) {
is PsiClass -> element.qualifiedName
is PsiField -> element.containingClass!!.qualifiedName + "#" + element.name
is PsiMethod ->
diff --git a/src/Java/JavadocParser.kt b/src/Java/JavadocParser.kt
new file mode 100644
index 00000000..1378a5a7
--- /dev/null
+++ b/src/Java/JavadocParser.kt
@@ -0,0 +1,170 @@
+package org.jetbrains.dokka
+
+import com.intellij.psi.*
+import com.intellij.psi.javadoc.PsiDocTag
+import com.intellij.psi.javadoc.PsiDocTagValue
+import com.intellij.psi.javadoc.PsiDocToken
+import com.intellij.psi.javadoc.PsiInlineDocTag
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+import org.jsoup.nodes.Node
+import org.jsoup.nodes.TextNode
+
+data class JavadocParseResult(val content: Content, val deprecatedContent: Content?) {
+ companion object {
+ val Empty = JavadocParseResult(Content.Empty, null)
+ }
+}
+
+interface JavaDocumentationParser {
+ fun parseDocumentation(element: PsiNamedElement): JavadocParseResult
+}
+
+class JavadocParser(private val refGraph: NodeReferenceGraph) : JavaDocumentationParser {
+ override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
+ val docComment = (element as? PsiDocCommentOwner)?.docComment
+ if (docComment == null) return JavadocParseResult.Empty
+ val result = MutableContent()
+ var deprecatedContent: Content? = null
+ val para = ContentParagraph()
+ result.append(para)
+ para.convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() })
+ docComment.tags.forEach { tag ->
+ when(tag.name) {
+ "see" -> result.convertSeeTag(tag)
+ "deprecated" -> {
+ deprecatedContent = Content()
+ deprecatedContent!!.convertJavadocElements(tag.contentElements())
+ }
+ else -> {
+ val subjectName = tag.getSubjectName()
+ val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
+
+ section.convertJavadocElements(tag.contentElements())
+ }
+ }
+ }
+ return JavadocParseResult(result, deprecatedContent)
+ }
+
+ private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
+ val tagValueElements = children
+ .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
+ .dropWhile { it is PsiWhiteSpace }
+ .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
+ return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
+ }
+
+ private fun ContentBlock.convertJavadocElements(elements: Iterable<PsiElement>) {
+ val htmlBuilder = StringBuilder()
+ elements.forEach {
+ if (it is PsiInlineDocTag) {
+ htmlBuilder.append(convertInlineDocTag(it))
+ } else {
+ htmlBuilder.append(it.text)
+ }
+ }
+ val doc = Jsoup.parse(htmlBuilder.toString().trimStart())
+ doc.body().childNodes().forEach {
+ convertHtmlNode(it)
+ }
+ }
+
+ private fun ContentBlock.convertHtmlNode(node: Node) {
+ if (node is TextNode) {
+ append(ContentText(node.text()))
+ } else if (node is Element) {
+ val childBlock = createBlock(node)
+ node.childNodes().forEach {
+ childBlock.convertHtmlNode(it)
+ }
+ append(childBlock)
+ }
+ }
+
+ private fun createBlock(element: Element): ContentBlock = when(element.tagName()) {
+ "p" -> ContentParagraph()
+ "b", "strong" -> ContentStrong()
+ "i", "em" -> ContentEmphasis()
+ "s", "del" -> ContentStrikethrough()
+ "code" -> ContentCode()
+ "pre" -> ContentBlockCode()
+ "ul" -> ContentUnorderedList()
+ "ol" -> ContentOrderedList()
+ "li" -> ContentListItem()
+ "a" -> createLink(element)
+ else -> ContentBlock()
+ }
+
+ private fun createLink(element: Element): ContentBlock {
+ val docref = element.attr("docref")
+ if (docref != null) {
+ return ContentNodeLazyLink(docref, { -> refGraph.lookup(docref)})
+ }
+ val href = element.attr("href")
+ if (href != null) {
+ return ContentExternalLink(href)
+ } else {
+ return ContentBlock()
+ }
+ }
+
+ private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
+ val linkElement = tag.linkElement()
+ if (linkElement == null) {
+ return
+ }
+ val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
+ val linkSignature = resolveLink(linkElement)
+ val text = ContentText(linkElement.text)
+ if (linkSignature != null) {
+ val linkNode = ContentNodeLazyLink(tag.valueElement!!.text, { -> refGraph.lookup(linkSignature)})
+ linkNode.append(text)
+ seeSection.append(linkNode)
+ } else {
+ seeSection.append(text)
+ }
+ }
+
+ private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.name) {
+ "link", "linkplain" -> {
+ val valueElement = tag.linkElement()
+ val linkSignature = resolveLink(valueElement)
+ if (linkSignature != null) {
+ val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
+ val link = "<a docref=\"$linkSignature\">${labelText.htmlEscape()}</a>"
+ if (tag.name == "link") "<code>$link</code>" else link
+ }
+ else if (valueElement != null) {
+ valueElement.text
+ } else {
+ ""
+ }
+ }
+ "code", "literal" -> {
+ val text = StringBuilder()
+ tag.dataElements.forEach { text.append(it.text) }
+ val escaped = text.toString().trimStart().htmlEscape()
+ if (tag.name == "code") "<code>$escaped</code>" else escaped
+ }
+ else -> tag.text
+ }
+
+ private fun PsiDocTag.linkElement(): PsiElement? =
+ valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
+
+ private fun resolveLink(valueElement: PsiElement?): String? {
+ val target = valueElement?.reference?.resolve()
+ if (target != null) {
+ return getSignature(target)
+ }
+ return null
+ }
+
+ fun PsiDocTag.getSubjectName(): String? {
+ if (name == "param" || name == "throws" || name == "exception") {
+ return valueElement?.text
+ }
+ return null
+ }
+}
diff --git a/src/Kotlin/DeclarationLinkResolver.kt b/src/Kotlin/DeclarationLinkResolver.kt
new file mode 100644
index 00000000..cd536768
--- /dev/null
+++ b/src/Kotlin/DeclarationLinkResolver.kt
@@ -0,0 +1,44 @@
+package org.jetbrains.dokka
+
+import com.google.inject.Inject
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
+import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
+
+class DeclarationLinkResolver
+ @Inject constructor(val resolutionFacade: ResolutionFacade,
+ val refGraph: NodeReferenceGraph,
+ val logger: DokkaLogger) {
+ fun resolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock {
+ val symbol = try {
+ val symbols = resolveKDocLink(resolutionFacade, fromDescriptor, null, href.split('.').toList())
+ findTargetSymbol(symbols)
+ } catch(e: Exception) {
+ null
+ }
+
+ // 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) {
+ return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) })
+ }
+ if ("/" in href) {
+ return ContentExternalLink(href)
+ }
+ logger.warn("Unresolved link to $href in doc comment of ${fromDescriptor.signatureWithSourceLocation()}")
+ return ContentExternalLink("#")
+ }
+
+ fun findTargetSymbol(symbols: Collection<DeclarationDescriptor>): DeclarationDescriptor? {
+ if (symbols.isEmpty()) {
+ return null
+ }
+ val symbol = symbols.first()
+ if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
+ return symbol.overriddenDescriptors.firstOrNull()
+ }
+ return symbol
+ }
+
+} \ No newline at end of file
diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt
index 7dc4075b..c48f1495 100644
--- a/src/Kotlin/DocumentationBuilder.kt
+++ b/src/Kotlin/DocumentationBuilder.kt
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
import org.jetbrains.kotlin.idea.kdoc.KDocFinder
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
@@ -62,6 +61,7 @@ interface PackageDocumentationBuilder {
class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
val session: ResolveSession,
+ val linkResolver: DeclarationLinkResolver,
val options: DocumentationOptions,
val refGraph: NodeReferenceGraph,
val logger: DokkaLogger) : JavaDocumentationBuilder {
@@ -98,7 +98,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
}
val tree = parseMarkdown(kdocText)
//println(tree.toTestString())
- val content = buildContent(tree, { href -> resolveContentLink(descriptor, href) })
+ val content = buildContent(tree, { href -> linkResolver.resolveContentLink(descriptor, href) })
if (kdoc is KDocSection) {
val tags = kdoc.getTags()
tags.forEach {
@@ -111,7 +111,7 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName())
val sectionContent = it.getContent()
val markdownNode = parseMarkdown(sectionContent)
- buildInlineContentTo(markdownNode, section, { href -> resolveContentLink(descriptor, href) })
+ buildInlineContentTo(markdownNode, section, { href -> linkResolver.resolveContentLink(descriptor, href) })
}
}
}
@@ -162,98 +162,13 @@ class DocumentationBuilder(val resolutionFacade: ResolutionFacade,
return Content.Empty to { node -> }
}
- fun DeclarationDescriptor.signature(): String = when(this) {
- is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString()
- is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "#" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + ":" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "<" + name
-
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
- }
-
- fun PropertyDescriptor.receiverSignature(): String {
- val receiver = extensionReceiverParameter
- if (receiver != null) {
- return "#" + receiver.type.signature()
- }
- return ""
- }
-
- fun CallableMemberDescriptor.parameterSignature(): String {
- val params = valueParameters.map { it.type }.toArrayList()
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- params.add(0, extensionReceiver.type)
- }
- return "(" + params.map { it.signature() }.joinToString() + ")"
- }
-
- fun KtType.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
- }
-
- fun DeclarationDescriptor.sourceLocation(): String? {
- if (this is DeclarationDescriptorWithSource) {
- val psi = (this.source as? PsiSourceElement)?.getPsi()
- if (psi != null) {
- val fileName = psi.containingFile.name
- val lineNumber = psi.lineNumber()
- return if (lineNumber != null) "$fileName:$lineNumber" else fileName
- }
- }
- return null
- }
-
- fun DeclarationDescriptor.signatureWithSourceLocation(): String {
- val signature = signature()
- val sourceLocation = sourceLocation()
- return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
- }
-
- fun resolveContentLink(descriptor: DeclarationDescriptor, href: String): ContentBlock {
- val symbol = try {
- val symbols = resolveKDocLink(resolutionFacade, descriptor, null, href.split('.').toList())
- findTargetSymbol(symbols)
- } catch(e: Exception) {
- null
- }
-
- // 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) {
- return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) })
- }
- if ("/" in href) {
- return ContentExternalLink(href)
- }
- logger.warn("Unresolved link to $href in doc comment of ${descriptor.signatureWithSourceLocation()}")
- return ContentExternalLink("#")
- }
-
- fun findTargetSymbol(symbols: Collection<DeclarationDescriptor>): DeclarationDescriptor? {
- if (symbols.isEmpty()) {
- return null
- }
- val symbol = symbols.first()
- if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
- return symbol.overriddenDescriptors.firstOrNull()
- }
- return symbol
- }
-
fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf()
private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) {
val subjectName = seeTag.getSubjectName()
if (subjectName != null) {
val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null)
- val link = resolveContentLink(descriptor, subjectName)
+ val link = linkResolver.resolveContentLink(descriptor, subjectName)
link.append(ContentText(subjectName))
val para = ContentParagraph()
para.append(link)
@@ -782,3 +697,56 @@ fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor
return null
}
+fun DeclarationDescriptor.signature(): String = when(this) {
+ is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString()
+ is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature()
+ is FunctionDescriptor -> containingDeclaration.signature() + "#" + name + parameterSignature()
+ is ValueParameterDescriptor -> containingDeclaration.signature() + ":" + name
+ is TypeParameterDescriptor -> containingDeclaration.signature() + "<" + name
+
+ else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
+}
+
+fun PropertyDescriptor.receiverSignature(): String {
+ val receiver = extensionReceiverParameter
+ if (receiver != null) {
+ return "#" + receiver.type.signature()
+ }
+ return ""
+}
+
+fun CallableMemberDescriptor.parameterSignature(): String {
+ val params = valueParameters.map { it.type }.toArrayList()
+ val extensionReceiver = extensionReceiverParameter
+ if (extensionReceiver != null) {
+ params.add(0, extensionReceiver.type)
+ }
+ return "(" + params.map { it.signature() }.joinToString() + ")"
+}
+
+fun KtType.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
+}
+
+fun DeclarationDescriptor.signatureWithSourceLocation(): String {
+ val signature = signature()
+ val sourceLocation = sourceLocation()
+ return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
+}
+
+fun DeclarationDescriptor.sourceLocation(): String? {
+ if (this is DeclarationDescriptorWithSource) {
+ val psi = (this.source as? PsiSourceElement)?.getPsi()
+ if (psi != null) {
+ val fileName = psi.containingFile.name
+ val lineNumber = psi.lineNumber()
+ return if (lineNumber != null) "$fileName:$lineNumber" else fileName
+ }
+ }
+ return null
+}
diff --git a/src/Model/PackageDocs.kt b/src/Model/PackageDocs.kt
index 99da327b..a1cfddf9 100644
--- a/src/Model/PackageDocs.kt
+++ b/src/Model/PackageDocs.kt
@@ -5,7 +5,7 @@ import org.intellij.markdown.MarkdownTokenTypes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import java.io.File
-public class PackageDocs(val documentationBuilder: DocumentationBuilder?,
+public class PackageDocs(val linkResolver: DeclarationLinkResolver?,
val linkResolveContext: DeclarationDescriptor?,
val logger: DokkaLogger) {
public val moduleContent: MutableContent = MutableContent()
@@ -48,8 +48,8 @@ public class PackageDocs(val documentationBuilder: DocumentationBuilder?,
_packageContent.getOrPut(packageName) { -> MutableContent() }
private fun resolveContentLink(href: String): ContentBlock {
- if (linkResolveContext != null && documentationBuilder != null) {
- return documentationBuilder.resolveContentLink(linkResolveContext, href)
+ if (linkResolveContext != null && linkResolver != null) {
+ return linkResolver.resolveContentLink(linkResolveContext, href)
}
return ContentExternalLink("#")
}
diff --git a/src/main.kt b/src/main.kt
index 46b9a2dc..1bb0d643 100644
--- a/src/main.kt
+++ b/src/main.kt
@@ -216,8 +216,9 @@ fun buildDocumentationModule(environment: AnalysisEnvironment,
val fragments = fragmentFiles.map { session.getPackageFragment(it.packageFqName) }.filterNotNull().distinct()
val refGraph = NodeReferenceGraph()
- val documentationBuilder = DocumentationBuilder(resolutionFacade, session, options, refGraph, logger)
- val packageDocs = PackageDocs(documentationBuilder, fragments.firstOrNull(), logger)
+ val linkResolver = DeclarationLinkResolver(resolutionFacade, refGraph, logger)
+ val documentationBuilder = DocumentationBuilder(resolutionFacade, session, linkResolver, options, refGraph, logger)
+ val packageDocs = PackageDocs(linkResolver, fragments.firstOrNull(), logger)
for (include in includes) {
packageDocs.parse(include)
}