aboutsummaryrefslogtreecommitdiff
path: root/dokka-subprojects/analysis-kotlin-api
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-11-22 18:39:22 +0100
committerGitHub <noreply@github.com>2023-11-22 18:39:22 +0100
commite63dad0875c8da8c2c04ac8a4285ad2507e74257 (patch)
treee70a6dac67794f5133f99a0c2a7e1530f2001697 /dokka-subprojects/analysis-kotlin-api
parent610b5520b02ce8275462793e176406d1fb37861c (diff)
downloaddokka-e63dad0875c8da8c2c04ac8a4285ad2507e74257.tar.gz
dokka-e63dad0875c8da8c2c04ac8a4285ad2507e74257.tar.bz2
dokka-e63dad0875c8da8c2c04ac8a4285ad2507e74257.zip
Stabilize ExternalDocumentableProvider (#3312)
Diffstat (limited to 'dokka-subprojects/analysis-kotlin-api')
-rw-r--r--dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api10
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt9
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider.kt54
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt28
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt2
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ExternalDocumentableProviderTest.kt342
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/README.md1
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/kotlinx-cli-jvm-0.3.6.jarbin0 -> 84592 bytes
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt2
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt1
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt3
-rw-r--r--dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt27
12 files changed, 444 insertions, 35 deletions
diff --git a/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api b/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api
index 3b546932..d15924b0 100644
--- a/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api
+++ b/dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api
@@ -1,8 +1,13 @@
public final class org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
public fun <init> ()V
+ public final fun getExternalDocumentableProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getSampleAnalysisEnvironmentCreator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
}
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider {
+ public abstract fun getClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
+}
+
public final class org/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage : java/lang/Enum {
public static final field JAVA Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage;
public static final field KOTLIN Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage;
@@ -14,10 +19,6 @@ public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/Doc
public abstract fun getLanguage (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage;
}
-public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider {
- public abstract fun findClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
-}
-
public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/FullClassHierarchyBuilder {
public abstract fun build (Lorg/jetbrains/dokka/model/DModule;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@@ -47,7 +48,6 @@ public final class org/jetbrains/dokka/analysis/kotlin/internal/InheritanceNode
public final class org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
public fun <init> ()V
public final fun getDocumentableSourceLanguageParser ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
- public final fun getExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getFullClassHierarchyBuilder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getInheritanceBuilder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getKotlinToJavaService ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
index 1df1dfe6..5a70b3f2 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt
@@ -4,6 +4,7 @@
package org.jetbrains.dokka.analysis.kotlin
+import org.jetbrains.dokka.analysis.kotlin.documentable.ExternalDocumentableProvider
import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreator
import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironment
import org.jetbrains.dokka.plugability.DokkaPlugin
@@ -20,6 +21,14 @@ public class KotlinAnalysisPlugin : DokkaPlugin() {
*/
public val sampleAnalysisEnvironmentCreator: ExtensionPoint<SampleAnalysisEnvironmentCreator> by extensionPoint()
+ /**
+ * An extension that helps to find external documentables that are not provided by Dokka by default,
+ * such as documentables that come from external dependencies.
+ *
+ * @see ExternalDocumentableProvider for more details
+ */
+ public val externalDocumentableProvider: ExtensionPoint<ExternalDocumentableProvider> by extensionPoint()
+
@OptIn(DokkaPluginApiPreview::class)
override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider.kt
new file mode 100644
index 00000000..6e2c7b33
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.kotlin.documentable
+
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.DClasslike
+import org.jetbrains.dokka.model.DClass
+import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator
+
+/**
+ * Helps find external documentables that are not provided by Dokka by default.
+ *
+ * By default, Dokka parses and makes available only documentables of the declarations found
+ * in the user project itself. Meaning, if the project's source code contains a `fun foo()`,
+ * it must be returned by [SourceToDocumentableTranslator]. However, if the user project
+ * depends on an external library which has a `fun bar()`, it will __not__ be available and
+ * documented out of the box.
+ *
+ * This provider helps you find documentables for the declarations that are present in
+ * [DokkaSourceSet.classpath] during runtime, but are not necessarily from the user project itself.
+ *
+ * For example, it can help you find a class that comes from a dependency, which can be useful
+ * if you want to get more information about a supertype of the project's class,
+ * because [DClass.supertypes] only provides the supertype's DRI, but not its full documentable.
+ *
+ * It is expected to work with all languages supported by the analysis implementation,
+ * meaning it should return Java classes if Java as an input language is supported.
+ *
+ * If you query DRIs of local project declarations (not external), it should generally work, although
+ * it's not guaranteed that the returned value will be 100% equal to that provided by Dokka by default.
+ *
+ * Note: because classpath entries consist of compiled code, the returned documentables may have some
+ * properties set to null or empty, because some information cannot be extracted from it in any way.
+ * One such example is KDocs, they are present in source code, but not in compiled classes.
+ */
+public interface ExternalDocumentableProvider {
+
+ /**
+ * Returns a valid and fully initialized [DClasslike] if the [dri] points to a class-like
+ * declaration (annotation, class, enum, interface, object) that can be found among
+ * [DokkaSourceSet.classpath] entries.
+ *
+ * If the [dri] points to a non-class-like declaration (like a function),
+ * or the declaration cannot be found, it returns `null`.
+ *
+ * Note: the implementation is not expected to cache results or return pre-computed values, so
+ * it may need to analyze parts of the project and instantiate new documentables on every invocation.
+ * Use this function sparingly, and cache results on your side if you need to.
+ */
+ public fun getClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike?
+}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt
deleted file mode 100644
index 7c564880..00000000
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package org.jetbrains.dokka.analysis.kotlin.internal
-
-import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.InternalDokkaApi
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.DClasslike
-
-/**
- * Service that can be queried with [DRI] and source set to obtain a documentable for classlike.
- *
- * There are some cases when there is a need to process documentables of classlikes that were not defined
- * in the project itself but are somehow related to the symbols defined in the documented project (e.g. are supertypes
- * of classes defined in project).
- */
-@InternalDokkaApi
-public fun interface ExternalDocumentablesProvider {
-
- /**
- * Returns [DClasslike] matching provided [DRI] in specified source set.
- *
- * Result is null if compiler haven't generated matching class descriptor.
- */
- public fun findClasslike(dri: DRI, sourceSet: DokkaConfiguration.DokkaSourceSet): DClasslike?
-}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
index d032d490..dbf33c8e 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt
@@ -27,8 +27,6 @@ public class InternalKotlinAnalysisPlugin : DokkaPlugin() {
public val inheritanceBuilder: ExtensionPoint<InheritanceBuilder> by extensionPoint()
- public val externalDocumentablesProvider: ExtensionPoint<ExternalDocumentablesProvider> by extensionPoint()
-
public val documentableSourceLanguageParser: ExtensionPoint<DocumentableSourceLanguageParser> by extensionPoint()
@OptIn(DokkaPluginApiPreview::class)
diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ExternalDocumentableProviderTest.kt b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ExternalDocumentableProviderTest.kt
new file mode 100644
index 00000000..2ef9e2f0
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ExternalDocumentableProviderTest.kt
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.analysis.test.documentable
+
+import org.jetbrains.dokka.analysis.test.api.javaTestProject
+import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject
+import org.jetbrains.dokka.analysis.test.api.useServices
+import org.jetbrains.dokka.analysis.test.api.util.getResourceAbsolutePath
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import kotlin.test.*
+
+class ExternalDocumentableProviderTest {
+
+ @Test
+ fun `should find a valid external class from java stdlib`() {
+ val project = javaTestProject {
+ javaFile("org/jetbrains/dokka/test/MyProjectJavaClass.java") {
+ +"public class MyProjectJavaClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyProjectJavaClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val arrayListDRI = DRI("java.util", "ArrayList")
+
+ val arrayListClasslike = externalDocumentableProvider.getClasslike(arrayListDRI, sourceSet)
+ assertNotNull(arrayListClasslike)
+
+ assertEquals("ArrayList", arrayListClasslike.name)
+ assertEquals(arrayListDRI, arrayListClasslike.dri)
+ assertTrue(arrayListClasslike is DClass)
+ assertTrue(arrayListClasslike.functions.size > 10, "java.util.ArrayList is expected to have >10 functions")
+
+ val superTypes = arrayListClasslike.supertypes.entries.single().value
+ val abstractListSuperType = superTypes.firstOrNull {
+ val dri = it.typeConstructor.dri
+ dri.packageName == "java.util" && dri.classNames == "AbstractList"
+ }
+ assertNotNull(abstractListSuperType, "java.util.ArrayList is expected to extend java.util.AbstractList")
+
+ }
+ }
+
+ @Test
+ fun `should find a valid external annotation from kotlin jvm stdlib`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val jvmFieldDRI = DRI("kotlin.jvm", "JvmField")
+
+ val jvmFieldAnnotation = externalDocumentableProvider.getClasslike(jvmFieldDRI, sourceSet)
+ assertNotNull(jvmFieldAnnotation)
+
+ assertEquals("JvmField", jvmFieldAnnotation.name)
+ assertEquals(jvmFieldDRI, jvmFieldAnnotation.dri)
+ assertTrue(jvmFieldAnnotation is DAnnotation)
+ }
+ }
+
+ @Test
+ fun `should find a valid external enum from kotlin stdlib`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val deprecationLevelDRI = DRI("kotlin", "DeprecationLevel")
+
+ val deprecationLevelEnum = externalDocumentableProvider.getClasslike(deprecationLevelDRI, sourceSet)
+ assertNotNull(deprecationLevelEnum)
+
+ assertEquals("DeprecationLevel", deprecationLevelEnum.name)
+ assertEquals(deprecationLevelDRI, deprecationLevelEnum.dri)
+ assertTrue(deprecationLevelEnum is DEnum)
+ assertEquals(3, deprecationLevelEnum.entries.size)
+
+ val warningLevel = deprecationLevelEnum.entries[0]
+ assertEquals("WARNING", warningLevel.name)
+ }
+ }
+
+ @Test
+ fun `should find a valid external interface from kotlin stdlib`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val sequenceDRI = DRI("kotlin.sequences", "Sequence")
+
+ val sequenceInterface = externalDocumentableProvider.getClasslike(sequenceDRI, sourceSet)
+ assertNotNull(sequenceInterface)
+
+ assertEquals("Sequence", sequenceInterface.name)
+ assertEquals(sequenceDRI, sequenceInterface.dri)
+ assertTrue(sequenceInterface is DInterface)
+
+ val iteratorFunction = sequenceInterface.functions.firstOrNull { it.name == "iterator" }
+ assertNotNull(iteratorFunction)
+ }
+ }
+
+ @Test
+ fun `should find a valid external object from kotlin stdlib`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val emptyCoroutineContextDRI = DRI("kotlin.coroutines", "EmptyCoroutineContext")
+
+ val emptyCoroutineContext = externalDocumentableProvider.getClasslike(emptyCoroutineContextDRI, sourceSet)
+ assertNotNull(emptyCoroutineContext)
+
+ assertEquals("EmptyCoroutineContext", emptyCoroutineContext.name)
+ assertEquals(emptyCoroutineContextDRI, emptyCoroutineContext.dri)
+ assertTrue(emptyCoroutineContext is DObject)
+ }
+ }
+
+ @Test
+ fun `should find a valid external class from a third party library`() {
+ val project = kotlinJvmTestProject {
+ dokkaConfiguration {
+ kotlinSourceSet {
+ additionalClasspath = setOf(
+ getResourceAbsolutePath("jars/kotlinx-cli-jvm-0.3.6.jar")
+ )
+ }
+ }
+
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val argTypeDRI = DRI("kotlinx.cli", "ArgType")
+
+ val argTypeClass = externalDocumentableProvider.getClasslike(argTypeDRI, sourceSet)
+ assertNotNull(argTypeClass)
+
+ assertEquals("ArgType", argTypeClass.name)
+ assertEquals(argTypeDRI, argTypeClass.dri)
+ assertTrue(argTypeClass is DClass)
+ assertEquals(KotlinModifier.Abstract, argTypeClass.modifier.values.single())
+ }
+ }
+
+ @Test
+ fun `should find a nested interface from java stdlib`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+ val mapEntryDRI = DRI("java.util", "Map.Entry")
+
+ val mapEntryInterface = externalDocumentableProvider.getClasslike(mapEntryDRI, sourceSet)
+ assertNotNull(mapEntryInterface)
+
+ assertEquals("Entry", mapEntryInterface.name)
+ assertEquals(mapEntryDRI, mapEntryInterface.dri)
+ assertTrue(mapEntryInterface is DInterface)
+ }
+ }
+
+ @Test
+ fun `should return null for querying non existing dri`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+
+ val nonExistingDRI = DRI("com.example.pckg", "NonExistingClassname")
+ val nonExistingClasslike = externalDocumentableProvider.getClasslike(nonExistingDRI, sourceSet)
+ assertNull(nonExistingClasslike)
+ }
+ }
+
+ @Test
+ fun `should return null for querying a classlike with a function dri`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ // first check that Dokka only returns documentables declared in the project by default
+ // to make sure later that the external documentable is indeed external and not local
+ val projectPackages = context.module.packages
+ assertEquals(1, projectPackages.size, "Expected only a single package to be returned")
+
+ val projectPackageChildren = projectPackages.single().children
+ assertEquals(1, projectPackageChildren.size, "Expected the project to contain only 1 child")
+ assertEquals("MyKotlinClass", projectPackageChildren.single().name)
+
+ // query for an external documentable that is not part of the project itself
+ val sourceSet = context.configuration.sourceSets.single()
+
+ val functionDRI = DRI("kotlin.collections", "listOf")
+ val queriedClasslike = externalDocumentableProvider.getClasslike(functionDRI, sourceSet)
+ assertNull(queriedClasslike)
+ }
+ }
+
+ @Test
+ fun `should return a class defined in the user project itself`() {
+ val project = kotlinJvmTestProject {
+ ktFile("org/jetbrains/test/dokka/MyKotlinFile.kt") {
+ +"class MyKotlinClass {}"
+ }
+ }
+
+ project.useServices { context ->
+ val sourceSet = context.configuration.sourceSets.single()
+
+ val userProjectClassDRI = DRI("org.jetbrains.test.dokka", "MyKotlinClass")
+ val userProjectClass = externalDocumentableProvider.getClasslike(userProjectClassDRI, sourceSet)
+ assertNotNull(userProjectClass)
+
+ assertEquals("MyKotlinClass", userProjectClass.name)
+ assertEquals(userProjectClassDRI, userProjectClass.dri)
+ assertTrue(userProjectClass is DClass)
+ }
+ }
+
+}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/README.md b/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/README.md
new file mode 100644
index 00000000..21f27d40
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/README.md
@@ -0,0 +1 @@
+The JARs in this directory can be used as external dependencies for testing purposes.
diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/kotlinx-cli-jvm-0.3.6.jar b/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/kotlinx-cli-jvm-0.3.6.jar
new file mode 100644
index 00000000..b4f1e5a4
--- /dev/null
+++ b/dokka-subprojects/analysis-kotlin-api/src/test/resources/jars/kotlinx-cli-jvm-0.3.6.jar
Binary files differ
diff --git a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt
index f729838d..714ee16a 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt
@@ -5,6 +5,7 @@
package org.jetbrains.dokka.analysis.test.api.analysis
import org.jetbrains.dokka.analysis.kotlin.KotlinAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.documentable.ExternalDocumentableProvider
import org.jetbrains.dokka.analysis.kotlin.internal.ModuleAndPackageDocumentationReader
import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreator
@@ -16,5 +17,6 @@ import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreat
*/
class TestAnalysisServices(
val sampleAnalysisEnvironmentCreator: SampleAnalysisEnvironmentCreator,
+ val externalDocumentableProvider: ExternalDocumentableProvider,
val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader
)
diff --git a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt
index 674c6d47..7a410d7d 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt
@@ -228,6 +228,7 @@ internal object TestProjectAnalyzer {
val internalAnalysisPlugin = context.plugin<InternalKotlinAnalysisPlugin>()
return TestAnalysisServices(
sampleAnalysisEnvironmentCreator = publicAnalysisPlugin.querySingle { sampleAnalysisEnvironmentCreator },
+ externalDocumentableProvider = publicAnalysisPlugin.querySingle { externalDocumentableProvider },
moduleAndPackageDocumentationReader = internalAnalysisPlugin.querySingle {
moduleAndPackageDocumentationReader
}
diff --git a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt
index b6563fb7..fc3499ea 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt
@@ -5,6 +5,7 @@
package org.jetbrains.dokka.analysis.test.api.configuration
import org.jetbrains.dokka.analysis.test.api.TestProject
+import org.jetbrains.dokka.analysis.test.api.util.getResourceAbsolutePath
import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker
/**
@@ -66,6 +67,8 @@ abstract class BaseTestDokkaSourceSetBuilder {
/**
* JARs **additional** to the default classpath.
*
+ * You can put test JARs inside `src/resources`, and then get it via [getResourceAbsolutePath].
+ *
* @see TestDokkaSourceSet.classpath
*/
open var additionalClasspath: Set<String> = emptySet()
diff --git a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt
index 779add8d..afa3e84a 100644
--- a/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt
+++ b/dokka-subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt
@@ -39,3 +39,30 @@ internal fun <T> withTempDirectory(logger: DokkaLogger? = null, block: (tempDire
logger?.debug("Deleted temporary directory $tempDir")
}
}
+
+/**
+ * Finds a resource by [resourcePath], and returns its absolute path.
+ *
+ * A resource is usually a file found in the `resources` directory of the project.
+ *
+ * For example, if you have a file `project/src/main/resources/jars/kotlinx-cli-jvm-0.3.6.jar`,
+ * you should be able to get it by calling this function as
+ * `getResourceAbsolutePath("jars/kotlinx-cli-jvm-0.3.6.jar")`.
+ *
+ * @throws IllegalArgumentException if the resource cannot be found or does not exist
+ * @return an absolute path to the resource, such as `/home/user/projects/dokka/../MyFile.md`
+ */
+fun getResourceAbsolutePath(resourcePath: String): String {
+ val resourceFile = getResourceFile(resourcePath)
+ require(resourceFile.exists()) {
+ "Resource file does not exist: $resourcePath"
+ }
+ return resourceFile.absolutePath
+}
+
+private fun getResourceFile(resourcePath: String): File {
+ val resource = object {}.javaClass.classLoader.getResource(resourcePath)?.file
+ ?: throw IllegalArgumentException("Resource not found: $resourcePath")
+
+ return File(resource)
+}