aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2018-05-04 21:35:02 +0300
committerSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2018-07-14 23:57:12 +0300
commitb00dabc4c53a71f745c29a135541b02f8dd7d266 (patch)
tree593b14e64d5a212da053f7842940b0a8081017f9 /core
parentcf8b820682cf7af82d15f46f742d63a7766fe95e (diff)
downloaddokka-b00dabc4c53a71f745c29a135541b02f8dd7d266.tar.gz
dokka-b00dabc4c53a71f745c29a135541b02f8dd7d266.tar.bz2
dokka-b00dabc4c53a71f745c29a135541b02f8dd7d266.zip
[backport] KT-24271: Support external link resolution in JavadocParser
Original: ace3914
Diffstat (limited to 'core')
-rw-r--r--core/src/main/kotlin/Analysis/AnalysisEnvironment.kt8
-rw-r--r--core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt10
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt51
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt12
-rw-r--r--core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt14
-rw-r--r--core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt30
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModules.kt3
7 files changed, 87 insertions, 41 deletions
diff --git a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
index 6854b323..d31fe187 100644
--- a/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
+++ b/core/src/main/kotlin/Analysis/AnalysisEnvironment.kt
@@ -99,7 +99,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
}
- fun createResolutionFacade(environment: KotlinCoreEnvironment): DokkaResolutionFacade {
+ fun createResolutionFacade(environment: KotlinCoreEnvironment): Pair<DokkaResolutionFacade, DokkaResolutionFacade> {
val projectContext = ProjectContext(environment.project)
val sourceFiles = environment.getSourceFiles()
@@ -164,15 +164,17 @@ class AnalysisEnvironment(val messageCollector: MessageCollector) : Disposable {
builtIns = builtIns
)
- resolverForProject.resolverForModule(library) // Required before module to initialize library properly
+ val resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly
val resolverForModule = resolverForProject.resolverForModule(module)
+ val libraryModuleDescriptor = resolverForProject.descriptorForModule(library)
val moduleDescriptor = resolverForProject.descriptorForModule(module)
builtIns.initialize(moduleDescriptor, true)
+ val libraryResolutionFacade = DokkaResolutionFacade(environment.project, libraryModuleDescriptor, resolverForLibrary)
val created = DokkaResolutionFacade(environment.project, moduleDescriptor, resolverForModule)
val projectComponentManager = environment.project as MockComponentManager
projectComponentManager.registerService(KotlinCacheService::class.java, CoreKotlinCacheService(created))
- return created
+ return created to libraryResolutionFacade
}
fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) {
diff --git a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
index 646096e5..8b30a6b4 100644
--- a/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
+++ b/core/src/main/kotlin/Java/JavaPsiDocumentationBuilder.kt
@@ -45,10 +45,16 @@ class JavaPsiDocumentationBuilder : JavaDocumentationBuilder {
private val refGraph: NodeReferenceGraph
private val docParser: JavaDocumentationParser
- @Inject constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, logger: DokkaLogger, signatureProvider: ElementSignatureProvider) {
+ @Inject constructor(
+ options: DocumentationOptions,
+ refGraph: NodeReferenceGraph,
+ logger: DokkaLogger,
+ signatureProvider: ElementSignatureProvider,
+ externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
+ ) {
this.options = options
this.refGraph = refGraph
- this.docParser = JavadocParser(refGraph, logger, signatureProvider)
+ this.docParser = JavadocParser(refGraph, logger, signatureProvider, externalDocumentationLinkResolver)
}
constructor(options: DocumentationOptions, refGraph: NodeReferenceGraph, docParser: JavaDocumentationParser) {
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
index 5e23e357..e1b15cb2 100644
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ b/core/src/main/kotlin/Java/JavadocParser.kt
@@ -26,7 +26,8 @@ interface JavaDocumentationParser {
class JavadocParser(
private val refGraph: NodeReferenceGraph,
private val logger: DokkaLogger,
- private val signatureProvider: ElementSignatureProvider
+ private val signatureProvider: ElementSignatureProvider,
+ private val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
) : JavaDocumentationParser {
private fun ContentSection.appendTypeElement(signature: String, selector: (DocumentationNode) -> DocumentationNode?) {
@@ -197,25 +198,41 @@ class JavadocParser(
private fun MutableContent.convertSeeTag(tag: PsiDocTag) {
val linkElement = tag.linkElement() ?: return
val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
- val linkSignature = resolveLink(tag.referenceElement())
+
+ val valueElement = tag.referenceElement()
+ val externalLink = resolveExternalLink(valueElement)
val text = ContentText(linkElement.text)
- if (linkSignature != null) {
- val linkNode =
- ContentNodeLazyLink((tag.valueElement ?: linkElement).text, { -> refGraph.lookupOrWarn(linkSignature, logger) })
- linkNode.append(text)
- seeSection.append(linkNode)
- } else {
- seeSection.append(text)
+
+ val linkSignature by lazy { resolveInternalLink(valueElement) }
+ val node = when {
+ externalLink != null -> {
+ val linkNode = ContentExternalLink(externalLink)
+ linkNode.append(text)
+ linkNode
+ }
+ linkSignature != null -> {
+ val linkNode =
+ ContentNodeLazyLink(
+ (tag.valueElement ?: linkElement).text,
+ { -> refGraph.lookupOrWarn(linkSignature, logger) }
+ )
+ linkNode.append(text)
+ linkNode
+ }
+ else -> text
}
+ seeSection.append(node)
}
private fun convertInlineDocTag(tag: PsiInlineDocTag, element: PsiNamedElement) = when (tag.name) {
"link", "linkplain" -> {
val valueElement = tag.referenceElement()
- val linkSignature = resolveLink(valueElement)
- if (linkSignature != null) {
+ val externalLink = resolveExternalLink(valueElement)
+ val linkSignature by lazy { resolveInternalLink(valueElement) }
+ if (externalLink != null || linkSignature != null) {
val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val link = "<a docref=\"$linkSignature\">${labelText.htmlEscape()}</a>"
+ val linkTarget = if (externalLink != null) "href=\"$externalLink\"" else "docref=\"$linkSignature\""
+ val link = "<a $linkTarget>${labelText.htmlEscape()}</a>"
if (tag.name == "link") "<code>$link</code>" else link
} else if (valueElement != null) {
valueElement.text
@@ -256,7 +273,15 @@ class JavadocParser(
private fun PsiDocTag.linkElement(): PsiElement? =
valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
- private fun resolveLink(valueElement: PsiElement?): String? {
+ private fun resolveExternalLink(valueElement: PsiElement?): String? {
+ val target = valueElement?.reference?.resolve()
+ if (target != null) {
+ return externalDocumentationLinkResolver.buildExternalDocumentationLink(target)
+ }
+ return null
+ }
+
+ private fun resolveInternalLink(valueElement: PsiElement?): String? {
val target = valueElement?.reference?.resolve()
if (target != null) {
return signatureProvider.signature(target)
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
index 5f1118e8..7817da18 100644
--- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
+++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt
@@ -34,8 +34,9 @@ class DescriptorDocumentationParser
val resolutionFacade: DokkaResolutionFacade,
val refGraph: NodeReferenceGraph,
val sampleService: SampleProcessingService,
- val signatureProvider: KotlinElementSignatureProvider
- )
+ val signatureProvider: KotlinElementSignatureProvider,
+ val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver
+)
{
fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false): Content =
parseDocumentationAndDetails(descriptor, inline).first
@@ -131,7 +132,12 @@ class DescriptorDocumentationParser
fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> {
val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
if (psi is PsiDocCommentOwner) {
- val parseResult = JavadocParser(refGraph, logger, signatureProvider).parseDocumentation(psi as PsiNamedElement)
+ val parseResult = JavadocParser(
+ refGraph,
+ logger,
+ signatureProvider,
+ externalDocumentationLinkResolver
+ ).parseDocumentation(psi as PsiNamedElement)
return parseResult.content to { node ->
parseResult.deprecatedContent?.let {
val deprecationNode = DocumentationNode("", it, NodeKind.Modifier)
diff --git a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
index 7be37177..c766b869 100644
--- a/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
+++ b/core/src/main/kotlin/Kotlin/ExternalDocumentationLinkResolver.kt
@@ -2,6 +2,7 @@ package org.jetbrains.dokka
import com.google.inject.Inject
import com.google.inject.Singleton
+import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.util.io.*
import org.jetbrains.dokka.Formats.FileGeneratorBasedFormatDescriptor
@@ -10,10 +11,7 @@ import org.jetbrains.dokka.Utilities.ServiceLocator
import org.jetbrains.dokka.Utilities.lookup
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
-import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
+import org.jetbrains.kotlin.load.java.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -25,6 +23,7 @@ import java.net.URL
import java.net.URLConnection
import java.nio.file.Path
import java.security.MessageDigest
+import javax.inject.Named
import kotlin.reflect.full.findAnnotation
fun ByteArray.toHexString() = this.joinToString(separator = "") { "%02x".format(it) }
@@ -32,6 +31,7 @@ fun ByteArray.toHexString() = this.joinToString(separator = "") { "%02x".format(
@Singleton
class ExternalDocumentationLinkResolver @Inject constructor(
val options: DocumentationOptions,
+ @Named("libraryResolutionFacade") val libraryResolutionFacade: DokkaResolutionFacade,
val logger: DokkaLogger
) {
@@ -166,6 +166,12 @@ class ExternalDocumentationLinkResolver @Inject constructor(
}
}
+ fun buildExternalDocumentationLink(element: PsiElement): String? {
+ return element.extractDescriptor(libraryResolutionFacade)?.let {
+ buildExternalDocumentationLink(it)
+ }
+ }
+
fun buildExternalDocumentationLink(symbol: DeclarationDescriptor): String? {
val packageFqName: FqName =
when (symbol) {
diff --git a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
index 0a377dc1..bcac0182 100644
--- a/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
+++ b/core/src/main/kotlin/Kotlin/KotlinElementSignatureProvider.kt
@@ -2,7 +2,6 @@ package org.jetbrains.dokka
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
-import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.PsiPackage
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -14,21 +13,22 @@ class KotlinElementSignatureProvider @Inject constructor(
val resolutionFacade: DokkaResolutionFacade
) : ElementSignatureProvider {
override fun signature(forPsi: PsiElement): String {
-
- val desc = when (forPsi) {
- is KtLightElement<*, *> -> return signature(forPsi.kotlinOrigin!!)
- is PsiPackage -> resolutionFacade.moduleDescriptor.getPackage(FqName(forPsi.qualifiedName))
- is PsiMember -> forPsi.getJavaOrKotlinMemberDescriptor(resolutionFacade)
- else -> resolutionFacade.resolveSession.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, forPsi]
- }
-
- if (desc == null && (forPsi as? PsiNameIdentifierOwner)?.name == "remove") {
- (forPsi as? PsiMember)?.getJavaOrKotlinMemberDescriptor(resolutionFacade)
- }
-
- return desc?.let { signature(it) }
+ return forPsi.extractDescriptor(resolutionFacade)
+ ?.let { signature(it) }
?: run { "no desc for $forPsi in ${(forPsi as? PsiMember)?.containingClass}" }
}
override fun signature(forDesc: DeclarationDescriptor): String = forDesc.signature()
-} \ No newline at end of file
+}
+
+
+fun PsiElement.extractDescriptor(resolutionFacade: DokkaResolutionFacade): DeclarationDescriptor? {
+ val forPsi = this
+
+ return when (forPsi) {
+ is KtLightElement<*, *> -> return (forPsi.kotlinOrigin!!).extractDescriptor(resolutionFacade)
+ is PsiPackage -> resolutionFacade.moduleDescriptor.getPackage(FqName(forPsi.qualifiedName))
+ is PsiMember -> forPsi.getJavaOrKotlinMemberDescriptor(resolutionFacade)
+ else -> resolutionFacade.resolveSession.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, forPsi]
+ }
+}
diff --git a/core/src/main/kotlin/Utilities/DokkaModules.kt b/core/src/main/kotlin/Utilities/DokkaModules.kt
index 907d5ca7..732cbc48 100644
--- a/core/src/main/kotlin/Utilities/DokkaModules.kt
+++ b/core/src/main/kotlin/Utilities/DokkaModules.kt
@@ -24,8 +24,9 @@ class DokkaAnalysisModule(val environment: AnalysisEnvironment,
val coreEnvironment = environment.createCoreEnvironment()
binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
- val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
+ val (dokkaResolutionFacade, libraryResolutionFacade) = environment.createResolutionFacade(coreEnvironment)
binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
+ binder.bind<DokkaResolutionFacade>().annotatedWith(Names.named("libraryResolutionFacade")).toInstance(libraryResolutionFacade)
binder.bind<DocumentationOptions>().toInstance(options)