aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvmishenev <vad-mishenev@yandex.ru>2021-09-21 21:38:44 +0300
committervmishenev <vad-mishenev@yandex.ru>2021-09-21 21:40:12 +0300
commit1ada27414d66e58b19e20a968834356e81dd26b2 (patch)
tree41a1f463df9f261fc8c0a7569088263310c227de
parent2c6169ad8c3f97e7b9f833879967497efd54ac2e (diff)
downloaddokka-1ada27414d66e58b19e20a968834356e81dd26b2.tar.gz
dokka-1ada27414d66e58b19e20a968834356e81dd26b2.tar.bz2
dokka-1ada27414d66e58b19e20a968834356e81dd26b2.zip
Fix link to javadoc enum entry (#2131)
-rw-r--r--core/api/core.api18
-rw-r--r--core/src/main/kotlin/links/DRI.kt21
-rw-r--r--kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt28
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt20
-rw-r--r--plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt78
-rw-r--r--plugins/base/src/test/kotlin/model/JavaTest.kt8
-rw-r--r--plugins/base/src/test/resources/locationProvider/jdk8-package-list217
7 files changed, 370 insertions, 20 deletions
diff --git a/core/api/core.api b/core/api/core.api
index ed83f3a7..24f103d7 100644
--- a/core/api/core.api
+++ b/core/api/core.api
@@ -460,6 +460,20 @@ public final class org/jetbrains/dokka/links/DRI$Companion {
public final fun getTopLevel ()Lorg/jetbrains/dokka/links/DRI;
}
+public final class org/jetbrains/dokka/links/DRIExtraContainer {
+ public fun <init> ()V
+ public fun <init> (Ljava/lang/String;)V
+ public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun encode ()Ljava/lang/String;
+ public final fun getData ()Ljava/lang/String;
+ public final fun getMap ()Ljava/util/Map;
+}
+
+public abstract class org/jetbrains/dokka/links/DRIExtraProperty {
+ public fun <init> ()V
+ public final fun getKey ()Ljava/lang/String;
+}
+
public final class org/jetbrains/dokka/links/DRIKt {
public static final fun getDriOfAny ()Lorg/jetbrains/dokka/links/DRI;
public static final fun getDriOfUnit ()Lorg/jetbrains/dokka/links/DRI;
@@ -478,6 +492,10 @@ public abstract class org/jetbrains/dokka/links/DriTarget {
public final class org/jetbrains/dokka/links/DriTarget$Companion {
}
+public final class org/jetbrains/dokka/links/EnumEntryDRIExtra : org/jetbrains/dokka/links/DRIExtraProperty {
+ public static final field INSTANCE Lorg/jetbrains/dokka/links/EnumEntryDRIExtra;
+}
+
public final class org/jetbrains/dokka/links/JavaClassReference : org/jetbrains/dokka/links/TypeReference {
public fun <init> (Ljava/lang/String;)V
public final fun component1 ()Ljava/lang/String;
diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt
index 25b9546f..c646934d 100644
--- a/core/src/main/kotlin/links/DRI.kt
+++ b/core/src/main/kotlin/links/DRI.kt
@@ -1,7 +1,10 @@
package org.jetbrains.dokka.links
+import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.CLASS
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.kotlin.readValue
/**
* [DRI] stands for DokkaResourceIdentifier
@@ -23,6 +26,24 @@ data class DRI(
}
}
+object EnumEntryDRIExtra: DRIExtraProperty<EnumEntryDRIExtra>()
+
+abstract class DRIExtraProperty<T> {
+ val key: String = this::class.qualifiedName
+ ?: (this.javaClass.let { it.`package`.name + "." + it.simpleName.ifEmpty { "anonymous" } })
+}
+
+class DRIExtraContainer(val data: String? = null) {
+ val map: MutableMap<String, Any> = if (data != null) ObjectMapper().readValue(data) else mutableMapOf()
+ inline operator fun <reified T> get(prop: DRIExtraProperty<T>): T? =
+ map[prop.key]?.let { prop as? T }
+
+ inline operator fun <reified T> set(prop: DRIExtraProperty<T>, value: T) =
+ value.also { map[prop.key] = it as Any }
+
+ fun encode(): String = ObjectMapper().writeValueAsString(map)
+}
+
val DriOfUnit = DRI("kotlin", "Unit")
val DriOfAny = DRI("kotlin", "Any")
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt
index 3dd28fed..5f74c429 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt
+++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt
@@ -1,10 +1,9 @@
package org.jetbrains.dokka.analysis
import com.intellij.psi.*
-import org.jetbrains.dokka.links.Callable
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.links.DriTarget
+import org.jetbrains.dokka.links.*
import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
@@ -14,13 +13,16 @@ fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWi
val callable = parameter?.containingDeclaration ?: firstIsInstanceOrNull<CallableDescriptor>()
DRI(
- firstIsInstanceOrNull<PackageFragmentDescriptor>()?.fqName?.asString() ?: "",
- (filterIsInstance<ClassDescriptor>() + filterIsInstance<TypeAliasDescriptor>()).toList()
+ packageName = firstIsInstanceOrNull<PackageFragmentDescriptor>()?.fqName?.asString() ?: "",
+ classNames = (filterIsInstance<ClassDescriptor>() + filterIsInstance<TypeAliasDescriptor>()).toList()
.takeIf { it.isNotEmpty() }
?.asReversed()
?.joinToString(separator = ".") { it.name.asString() },
- callable?.let { Callable.from(it) },
- DriTarget.from(parameter ?: descriptor)
+ callable = callable?.let { Callable.from(it) },
+ target = DriTarget.from(parameter ?: descriptor),
+ extra = if (descriptor is EnumEntrySyntheticClassDescriptor)
+ DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
+ else null
)
}
@@ -30,9 +32,13 @@ fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run {
val classes = filterIsInstance<PsiClass>().filterNot { it is PsiTypeParameter }
.toList() // We only want exact PsiClass types, not PsiTypeParameter subtype
DRI(
- classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', "") ?: "",
- classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }?.joinToString("."),
- psiMethod?.let { Callable.from(it) } ?: psiField?.let { Callable.from(it) },
- DriTarget.from(psi)
+ packageName = classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', "") ?: "",
+ classNames = classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }
+ ?.joinToString("."),
+ callable = psiMethod?.let { Callable.from(it) } ?: psiField?.let { Callable.from(it) },
+ target = DriTarget.from(psi),
+ extra = if (psi is PsiEnumConstant)
+ DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
+ else null
)
}
diff --git a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt
index f1a32cb4..84445d2a 100644
--- a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt
+++ b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt
@@ -2,8 +2,7 @@ package org.jetbrains.dokka.base.resolvers.external.javadoc
import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider
import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation
-import org.jetbrains.dokka.links.Callable
-import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.utilities.htmlEscape
@@ -30,8 +29,21 @@ open class JavadocExternalLocationProvider(
if (classNames == null) {
return "$docWithModule$packageLink/package-summary$extension".htmlEscape()
}
- val classLink =
- if (packageLink == null) "${classNames}$extension" else "$packageLink/${classNames}$extension"
+
+ // in Kotlin DRI of enum entry is not callable
+ if (DRIExtraContainer(extra)[EnumEntryDRIExtra] != null) {
+ val (classSplit, enumEntityAnchor) = if (callable == null) {
+ val lastIndex = classNames?.lastIndexOf(".") ?: 0
+ classNames?.substring(0, lastIndex) to classNames?.substring(lastIndex + 1)
+ } else
+ classNames to callable?.name
+
+ val classLink =
+ if (packageLink == null) "${classSplit}$extension" else "$packageLink/${classSplit}$extension"
+ return "$docWithModule$classLink#$enumEntityAnchor".htmlEscape()
+ }
+
+ val classLink = if (packageLink == null) "${classNames}$extension" else "$packageLink/${classNames}$extension"
val callableChecked = callable ?: return "$docWithModule$classLink".htmlEscape()
return ("$docWithModule$classLink#" + anchorPart(callableChecked)).htmlEscape()
diff --git a/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt
new file mode 100644
index 00000000..cb2b0331
--- /dev/null
+++ b/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt
@@ -0,0 +1,78 @@
+package locationProvider
+
+import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocationProvider
+import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation
+import org.jetbrains.dokka.base.resolvers.shared.PackageList
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
+import org.jetbrains.dokka.links.*
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Test
+import java.net.URL
+
+class JavadocExternalLocationProviderTest : BaseAbstractTest() {
+ private val testDataDir =
+ getTestDataDir("locationProvider").toAbsolutePath().toString().removePrefix("/").let { "/$it" }
+
+ private val jdk = "https://docs.oracle.com/javase/8/docs/api/"
+ private val jdkPackageListURL = URL("file://$testDataDir/jdk8-package-list")
+
+ private val configuration = dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("src/")
+ classpath += jvmStdlibPath!!
+ }
+ }
+ }
+
+ private fun getTestLocationProvider(context: DokkaContext? = null): DefaultExternalLocationProvider {
+ val dokkaContext = context ?: DokkaContext.create(configuration, logger, emptyList())
+ val packageList = PackageList.load(jdkPackageListURL, 8, true)!!
+ val externalDocumentation =
+ ExternalDocumentation(URL(jdk), packageList)
+ return JavadocExternalLocationProvider(externalDocumentation, "--", "-", dokkaContext)
+ }
+
+ @Test
+ fun `link to enum entity of javadoc`() {
+ val locationProvider = getTestLocationProvider()
+ val ktDri = DRI(
+ "java.nio.file",
+ "StandardOpenOption.CREATE",
+ extra = DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
+ )
+ val javaDri = DRI(
+ "java.nio.file",
+ "StandardOpenOption",
+ Callable("CREATE", null, emptyList()),
+ PointingToDeclaration,
+ DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
+ )
+
+ assertEquals(
+ "https://docs.oracle.com/javase/8/docs/api/java/nio/file/StandardOpenOption.html#CREATE",
+ locationProvider.resolve(ktDri)
+ )
+
+ assertEquals(
+ "https://docs.oracle.com/javase/8/docs/api/java/nio/file/StandardOpenOption.html#CREATE",
+ locationProvider.resolve(javaDri)
+ )
+ }
+
+ @Test
+ fun `link to nested class of javadoc`() {
+ val locationProvider = getTestLocationProvider()
+ val dri = DRI(
+ "java.rmi.activation",
+ "ActivationGroupDesc.CommandEnvironment"
+ )
+
+ assertEquals(
+ "https://docs.oracle.com/javase/8/docs/api/java/rmi/activation/ActivationGroupDesc.CommandEnvironment.html",
+ locationProvider.resolve(dri)
+ )
+ }
+}
diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt
index da45a920..991b48ef 100644
--- a/plugins/base/src/test/kotlin/model/JavaTest.kt
+++ b/plugins/base/src/test/kotlin/model/JavaTest.kt
@@ -2,10 +2,7 @@ package model
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.links.JavaClassReference
-import org.jetbrains.dokka.links.PointingToDeclaration
-import org.jetbrains.dokka.links.sureClassNames
+import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.doc.Param
import org.jetbrains.dokka.model.doc.Text
@@ -369,7 +366,8 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") {
"java.lang.annotation",
"RetentionPolicy",
DRICallable("RUNTIME", null, emptyList()),
- PointingToDeclaration
+ PointingToDeclaration,
+ DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
)
)
diff --git a/plugins/base/src/test/resources/locationProvider/jdk8-package-list b/plugins/base/src/test/resources/locationProvider/jdk8-package-list
new file mode 100644
index 00000000..351c1868
--- /dev/null
+++ b/plugins/base/src/test/resources/locationProvider/jdk8-package-list
@@ -0,0 +1,217 @@
+java.applet
+java.awt
+java.awt.color
+java.awt.datatransfer
+java.awt.dnd
+java.awt.event
+java.awt.font
+java.awt.geom
+java.awt.im
+java.awt.im.spi
+java.awt.image
+java.awt.image.renderable
+java.awt.print
+java.beans
+java.beans.beancontext
+java.io
+java.lang
+java.lang.annotation
+java.lang.instrument
+java.lang.invoke
+java.lang.management
+java.lang.ref
+java.lang.reflect
+java.math
+java.net
+java.nio
+java.nio.channels
+java.nio.channels.spi
+java.nio.charset
+java.nio.charset.spi
+java.nio.file
+java.nio.file.attribute
+java.nio.file.spi
+java.rmi
+java.rmi.activation
+java.rmi.dgc
+java.rmi.registry
+java.rmi.server
+java.security
+java.security.acl
+java.security.cert
+java.security.interfaces
+java.security.spec
+java.sql
+java.text
+java.text.spi
+java.time
+java.time.chrono
+java.time.format
+java.time.temporal
+java.time.zone
+java.util
+java.util.concurrent
+java.util.concurrent.atomic
+java.util.concurrent.locks
+java.util.function
+java.util.jar
+java.util.logging
+java.util.prefs
+java.util.regex
+java.util.spi
+java.util.stream
+java.util.zip
+javax.accessibility
+javax.activation
+javax.activity
+javax.annotation
+javax.annotation.processing
+javax.crypto
+javax.crypto.interfaces
+javax.crypto.spec
+javax.imageio
+javax.imageio.event
+javax.imageio.metadata
+javax.imageio.plugins.bmp
+javax.imageio.plugins.jpeg
+javax.imageio.spi
+javax.imageio.stream
+javax.jws
+javax.jws.soap
+javax.lang.model
+javax.lang.model.element
+javax.lang.model.type
+javax.lang.model.util
+javax.management
+javax.management.loading
+javax.management.modelmbean
+javax.management.monitor
+javax.management.openmbean
+javax.management.relation
+javax.management.remote
+javax.management.remote.rmi
+javax.management.timer
+javax.naming
+javax.naming.directory
+javax.naming.event
+javax.naming.ldap
+javax.naming.spi
+javax.net
+javax.net.ssl
+javax.print
+javax.print.attribute
+javax.print.attribute.standard
+javax.print.event
+javax.rmi
+javax.rmi.CORBA
+javax.rmi.ssl
+javax.script
+javax.security.auth
+javax.security.auth.callback
+javax.security.auth.kerberos
+javax.security.auth.login
+javax.security.auth.spi
+javax.security.auth.x500
+javax.security.cert
+javax.security.sasl
+javax.sound.midi
+javax.sound.midi.spi
+javax.sound.sampled
+javax.sound.sampled.spi
+javax.sql
+javax.sql.rowset
+javax.sql.rowset.serial
+javax.sql.rowset.spi
+javax.swing
+javax.swing.border
+javax.swing.colorchooser
+javax.swing.event
+javax.swing.filechooser
+javax.swing.plaf
+javax.swing.plaf.basic
+javax.swing.plaf.metal
+javax.swing.plaf.multi
+javax.swing.plaf.nimbus
+javax.swing.plaf.synth
+javax.swing.table
+javax.swing.text
+javax.swing.text.html
+javax.swing.text.html.parser
+javax.swing.text.rtf
+javax.swing.tree
+javax.swing.undo
+javax.tools
+javax.transaction
+javax.transaction.xa
+javax.xml
+javax.xml.bind
+javax.xml.bind.annotation
+javax.xml.bind.annotation.adapters
+javax.xml.bind.attachment
+javax.xml.bind.helpers
+javax.xml.bind.util
+javax.xml.crypto
+javax.xml.crypto.dom
+javax.xml.crypto.dsig
+javax.xml.crypto.dsig.dom
+javax.xml.crypto.dsig.keyinfo
+javax.xml.crypto.dsig.spec
+javax.xml.datatype
+javax.xml.namespace
+javax.xml.parsers
+javax.xml.soap
+javax.xml.stream
+javax.xml.stream.events
+javax.xml.stream.util
+javax.xml.transform
+javax.xml.transform.dom
+javax.xml.transform.sax
+javax.xml.transform.stax
+javax.xml.transform.stream
+javax.xml.validation
+javax.xml.ws
+javax.xml.ws.handler
+javax.xml.ws.handler.soap
+javax.xml.ws.http
+javax.xml.ws.soap
+javax.xml.ws.spi
+javax.xml.ws.spi.http
+javax.xml.ws.wsaddressing
+javax.xml.xpath
+org.ietf.jgss
+org.omg.CORBA
+org.omg.CORBA.DynAnyPackage
+org.omg.CORBA.ORBPackage
+org.omg.CORBA.TypeCodePackage
+org.omg.CORBA.portable
+org.omg.CORBA_2_3
+org.omg.CORBA_2_3.portable
+org.omg.CosNaming
+org.omg.CosNaming.NamingContextExtPackage
+org.omg.CosNaming.NamingContextPackage
+org.omg.Dynamic
+org.omg.DynamicAny
+org.omg.DynamicAny.DynAnyFactoryPackage
+org.omg.DynamicAny.DynAnyPackage
+org.omg.IOP
+org.omg.IOP.CodecFactoryPackage
+org.omg.IOP.CodecPackage
+org.omg.Messaging
+org.omg.PortableInterceptor
+org.omg.PortableInterceptor.ORBInitInfoPackage
+org.omg.PortableServer
+org.omg.PortableServer.CurrentPackage
+org.omg.PortableServer.POAManagerPackage
+org.omg.PortableServer.POAPackage
+org.omg.PortableServer.ServantLocatorPackage
+org.omg.PortableServer.portable
+org.omg.SendingContext
+org.omg.stub.java.rmi
+org.w3c.dom
+org.w3c.dom.bootstrap
+org.w3c.dom.events
+org.w3c.dom.ls
+org.w3c.dom.views
+org.xml.sax
+org.xml.sax.ext
+org.xml.sax.helpers