Skip to content

Commit

Permalink
Add KDocs
Browse files Browse the repository at this point in the history
  • Loading branch information
IgnatBeresnev committed Nov 22, 2023
1 parent b4f72a5 commit c5cd408
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public final class org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin : or
}

public abstract interface class org/jetbrains/dokka/analysis/kotlin/documentable/ExternalDocumentableProvider {
public abstract fun findClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ public class KotlinAnalysisPlugin : DokkaPlugin() {
public val sampleAnalysisEnvironmentCreator: ExtensionPoint<SampleAnalysisEnvironmentCreator> by extensionPoint()

/**
* TODO [external-documentable-provider] add documentation
* 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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,48 @@ 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

/**
* TODO [external-documentable-provider] add documentation
* Helps find external documentables that are not provided by Dokka by default.
*
* By default, Dokka parses and makes available only documentables for 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 {

/**
* TODO [external-documentable-provider] add documentation
* 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 findClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike?
public fun getClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike?
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val arrayListDRI = DRI("java.util", "ArrayList")

val arrayListClasslike = externalDocumentableProvider.findClasslike(arrayListDRI, sourceSet)
val arrayListClasslike = externalDocumentableProvider.getClasslike(arrayListDRI, sourceSet)
assertNotNull(arrayListClasslike)

assertEquals("ArrayList", arrayListClasslike.name)
Expand Down Expand Up @@ -78,7 +78,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val jvmFieldDRI = DRI("kotlin.jvm", "JvmField")

val jvmFieldAnnotation = externalDocumentableProvider.findClasslike(jvmFieldDRI, sourceSet)
val jvmFieldAnnotation = externalDocumentableProvider.getClasslike(jvmFieldDRI, sourceSet)
assertNotNull(jvmFieldAnnotation)

assertEquals("JvmField", jvmFieldAnnotation.name)
Expand Down Expand Up @@ -110,7 +110,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val deprecationLevelDRI = DRI("kotlin", "DeprecationLevel")

val deprecationLevelEnum = externalDocumentableProvider.findClasslike(deprecationLevelDRI, sourceSet)
val deprecationLevelEnum = externalDocumentableProvider.getClasslike(deprecationLevelDRI, sourceSet)
assertNotNull(deprecationLevelEnum)

assertEquals("DeprecationLevel", deprecationLevelEnum.name)
Expand Down Expand Up @@ -146,7 +146,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val sequenceDRI = DRI("kotlin.sequences", "Sequence")

val sequenceInterface = externalDocumentableProvider.findClasslike(sequenceDRI, sourceSet)
val sequenceInterface = externalDocumentableProvider.getClasslike(sequenceDRI, sourceSet)
assertNotNull(sequenceInterface)

assertEquals("Sequence", sequenceInterface.name)
Expand Down Expand Up @@ -181,7 +181,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val emptyCoroutineContextDRI = DRI("kotlin.coroutines", "EmptyCoroutineContext")

val emptyCoroutineContext = externalDocumentableProvider.findClasslike(emptyCoroutineContextDRI, sourceSet)
val emptyCoroutineContext = externalDocumentableProvider.getClasslike(emptyCoroutineContextDRI, sourceSet)
assertNotNull(emptyCoroutineContext)

assertEquals("EmptyCoroutineContext", emptyCoroutineContext.name)
Expand Down Expand Up @@ -221,7 +221,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val argTypeDRI = DRI("kotlinx.cli", "ArgType")

val argTypeClass = externalDocumentableProvider.findClasslike(argTypeDRI, sourceSet)
val argTypeClass = externalDocumentableProvider.getClasslike(argTypeDRI, sourceSet)
assertNotNull(argTypeClass)

assertEquals("ArgType", argTypeClass.name)
Expand Down Expand Up @@ -254,7 +254,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()
val mapEntryDRI = DRI("java.util", "Map.Entry")

val mapEntryInterface = externalDocumentableProvider.findClasslike(mapEntryDRI, sourceSet)
val mapEntryInterface = externalDocumentableProvider.getClasslike(mapEntryDRI, sourceSet)
assertNotNull(mapEntryInterface)

assertEquals("Entry", mapEntryInterface.name)
Expand Down Expand Up @@ -286,7 +286,7 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()

val nonExistingDRI = DRI("com.example.pckg", "NonExistingClassname")
val nonExistingClasslike = externalDocumentableProvider.findClasslike(nonExistingDRI, sourceSet)
val nonExistingClasslike = externalDocumentableProvider.getClasslike(nonExistingDRI, sourceSet)
assertNull(nonExistingClasslike)
}
}
Expand All @@ -313,8 +313,30 @@ class ExternalDocumentableProviderTest {
val sourceSet = context.configuration.sourceSets.single()

val functionDRI = DRI("kotlin.collections", "listOf")
val queriedClasslike = externalDocumentableProvider.findClasslike(functionDRI, sourceSet)
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)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,16 @@ internal fun <T> withTempDirectory(logger: DokkaLogger? = null, block: (tempDire
}

/**
* TODO [external-documentable-provider] add documentation
* 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)
Expand All @@ -51,10 +60,7 @@ fun getResourceAbsolutePath(resourcePath: String): String {
return resourceFile.absolutePath
}

/**
* TODO [external-documentable-provider] add documentation
*/
fun getResourceFile(resourcePath: String): File {
private fun getResourceFile(resourcePath: String): File {
val resource = object {}.javaClass.classLoader.getResource(resourcePath)?.file
?: throw IllegalArgumentException("Resource not found: $resourcePath")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal class DescriptorExternalDocumentablesProvider(context: DokkaContext) :

private val translator: ExternalClasslikesTranslator = DefaultDescriptorToDocumentableTranslator(context)

override fun findClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? {
override fun getClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? {
val pkg = dri.packageName?.let { FqName(it) } ?: FqName.ROOT
val names = dri.classNames?.split('.') ?: return null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.jetbrains.dokka.analysis.kotlin.documentable.ExternalDocumentableProv
internal class SymbolExternalDocumentablesProvider(val context: DokkaContext) : ExternalDocumentableProvider {
private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis }

override fun findClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? {
override fun getClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? {
val classId = getClassIdFromDRI(dri)

return analyze(kotlinAnalysis.getModule(sourceSet)) {
Expand Down

0 comments on commit c5cd408

Please sign in to comment.