Skip to content

Commit

Permalink
Support Dokka K2 analysis (#3094)
Browse files Browse the repository at this point in the history
Dokka has its own documentable model to represent analyzed code. The analysis is performed by a compiler frontend.

In K1 the compiler frontend has descriptors that use the underlying Binding Context (global shared stateful structure). Dokka just maps descriptors to Documentable by DefaultDescriptorToDocumentableTranslator.

K2 compiler has FIR tree, which means “Frontend Intermediate Representation”, instead of Binding Context. But we do not use FIR in Dokka directly, since it is too low-level for analysis. The Kotlin compiler provides high-level Analysis API for this case. The API is used by KSP too. Analysis API represent elements of FIR (declarations, parameters and so on) as Symbols. For more details see KtSymbolByFirBuilder, KtSymbol.
For Dokka symbol is the replacement of descriptor in K2.

Also, to set up the environment of project analysis in K1 we use idea dependencies (or copy-past from there). In K2 for these aims, there is a Standalone mode for Analysis API.
  • Loading branch information
vmishenev authored Aug 28, 2023
1 parent bec2cac commit 0e00edc
Show file tree
Hide file tree
Showing 98 changed files with 3,555 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.jetbrains.conventions

/**
* Utility to run ynit tests for K1 and K2 (analysis API).
*/

plugins {
id("org.jetbrains.conventions.base")
id("org.jetbrains.conventions.base-java")
}

val descriptorsTestConfiguration: Configuration by configurations.creating {
extendsFrom(configurations.testImplementation.get())
}
val symbolsTestConfiguration: Configuration by configurations.creating {
extendsFrom(configurations.testImplementation.get())
}

val symbolsTest = tasks.register<Test>("symbolsTest") {
useJUnitPlatform {
excludeTags("onlyDescriptors", "onlyDescriptorsMPP", "javaCode", "usingJDK")
}
classpath += symbolsTestConfiguration
}
// run symbols and descriptors tests
tasks.test {
//enabled = false
classpath += descriptorsTestConfiguration
dependsOn(symbolsTest)
}

val descriptorsTest = tasks.register<Test>("descriptorsTest") {
classpath += descriptorsTestConfiguration
}

tasks.check {
dependsOn(symbolsTest)
}

16 changes: 16 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ gradlePlugin-android = "4.2.2"
gradlePlugin-dokka = "1.8.20"

kotlinx-coroutines = "1.6.3"
kotlinx-collections-immutable = "0.3.4"
kotlinx-bcv = "0.12.1"

## Analysis
kotlin-compiler = "1.9.0"
kotlin-compiler-k2 = "1.9.0-release-358"

# MUST match the version of the intellij platform used in the kotlin compiler,
# otherwise this will lead to different versions of psi API and implementations
Expand Down Expand Up @@ -56,6 +58,7 @@ eclipse-jgit = "5.12.0.202106070339-r"
[libraries]

kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm", version.ref = "kotlinx-collections-immutable" }

#### Gradle plugins ####
# The Maven coordinates of Gradle plugins that are either used in convention plugins, or in Dokka subprojects
Expand All @@ -68,6 +71,19 @@ gradlePlugin-gradlePublish= { module = "com.gradle.publish:plugin-publish-plugin
#### Kotlin analysis ####
kotlin-compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin-compiler" }

###### K2 analysis ######
kotlin-compiler-k2 = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin-compiler-k2" }
kotlin-high-level-api-api = { module = "org.jetbrains.kotlin:high-level-api-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-high-level-api-impl = { module = "org.jetbrains.kotlin:high-level-api-impl-base-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-high-level-api-fir = { module = "org.jetbrains.kotlin:high-level-api-fir-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-high-level-api-fe10 = { module = "org.jetbrains.kotlin:high-level-api-fe10-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-low-level-api-fir = { module = "org.jetbrains.kotlin:low-level-api-fir-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-analysis-project-structure = { module = "org.jetbrains.kotlin:analysis-project-structure-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-analysis-api-standalone = { module = "org.jetbrains.kotlin:analysis-api-standalone-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-analysis-api-providers = { module = "org.jetbrains.kotlin:analysis-api-providers-for-ide", version.ref = "kotlin-compiler-k2" }
kotlin-symbol-light-classes = { module = "org.jetbrains.kotlin:symbol-light-classes-for-ide", version.ref = "kotlin-compiler-k2" }


#### Java analysis ####
intellij-java-psi-api = { module = "com.jetbrains.intellij.java:java-psi", version.ref = "intellij-platform" }
intellij-java-psi-impl = { module = "com.jetbrains.intellij.java:java-psi-impl", version.ref = "intellij-platform" }
Expand Down
8 changes: 7 additions & 1 deletion plugins/android-documentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import org.jetbrains.registerDokkaArtifactPublication
plugins {
id("org.jetbrains.conventions.kotlin-jvm")
id("org.jetbrains.conventions.maven-publish")
id("org.jetbrains.conventions.base-unit-test")
}

dependencies {
Expand All @@ -13,10 +14,15 @@ dependencies {
implementation(kotlin("reflect"))

testImplementation(projects.plugins.base)
testImplementation(projects.plugins.base.baseTestUtils)
testImplementation(projects.core.testApi)
testImplementation(platform(libs.junit.bom))
testImplementation(libs.junit.jupiter)

symbolsTestConfiguration(project(path = ":subprojects:analysis-kotlin-symbols", configuration = "shadow"))
descriptorsTestConfiguration(project(path = ":subprojects:analysis-kotlin-descriptors", configuration = "shadow"))
testImplementation(projects.plugins.base.baseTestUtils) {
exclude(module = "analysis-kotlin-descriptors")
}
}

registerDokkaArtifactPublication("androidDocumentationPlugin") {
Expand Down
1 change: 1 addition & 0 deletions plugins/base/base-test-utils/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies {
api(projects.subprojects.analysisKotlinApi)

// TODO [beresnev] analysis switcher
//runtimeOnly(project(path = ":subprojects:analysis-kotlin-symbols", configuration = "shadow"))
runtimeOnly(project(path = ":subprojects:analysis-kotlin-descriptors", configuration = "shadow"))

implementation(kotlin("reflect"))
Expand Down
13 changes: 12 additions & 1 deletion plugins/base/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id("org.jetbrains.conventions.kotlin-jvm")
id("org.jetbrains.conventions.maven-publish")
id("org.jetbrains.conventions.dokka-html-frontend-files")
id("org.jetbrains.conventions.base-unit-test")
}

dependencies {
Expand All @@ -26,7 +27,11 @@ dependencies {
}

// Test only
testImplementation(projects.plugins.base.baseTestUtils)
symbolsTestConfiguration(project(path = ":subprojects:analysis-kotlin-symbols", configuration = "shadow"))
descriptorsTestConfiguration(project(path = ":subprojects:analysis-kotlin-descriptors", configuration = "shadow"))
testImplementation(projects.plugins.base.baseTestUtils) {
exclude(module = "analysis-kotlin-descriptors")
}
testImplementation(projects.core.contentMatcherTestUtils)
testImplementation(projects.core.testApi)
testImplementation(platform(libs.junit.bom))
Expand All @@ -37,6 +42,12 @@ dependencies {
}
}







// access the frontend files via the dependency on :plugins:base:frontend
val dokkaHtmlFrontendFiles: Provider<FileCollection> =
configurations.dokkaHtmlFrontendFiles.map { frontendFiles ->
Expand Down
1 change: 1 addition & 0 deletions plugins/base/src/test/kotlin/basic/DRITest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jetbrains.dokka.pages.ClasslikePageNode
import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.pages.MemberPageNode
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test

class DRITest : BaseAbstractTest() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import org.jetbrains.dokka.pages.ContentText
import org.jetbrains.dokka.pages.MemberPageNode
import org.jetbrains.dokka.pages.PackagePageNode
import org.junit.jupiter.api.Test
import utils.ParamAttributes
import utils.assertNotNull
import utils.bareSignature
import utils.propertySignature
import utils.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue

Expand Down Expand Up @@ -318,6 +315,7 @@ class ContentForAnnotationsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `annotated bounds in Java`() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.ContentPage
import org.jetbrains.dokka.pages.ContentStyle
import org.junit.jupiter.api.Test
import utils.JavaCode
import utils.pWrapped
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@JavaCode
class JavaDeprecatedTest : BaseAbstractTest() {

private val testConfiguration = dokkaConfiguration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.model.DisplaySourceSet
import org.junit.jupiter.api.Test
import utils.ParamAttributes
import utils.bareSignature
import utils.findTestType
import utils.*
import kotlin.test.assertEquals

class ContentForExceptions : BaseAbstractTest() {
Expand Down Expand Up @@ -55,6 +53,7 @@ class ContentForExceptions : BaseAbstractTest() {
)
}

@OnlyDescriptors("Fixed in 1.9.20 (IMPORT STAR)")
@Test
fun `function with navigatable thrown exception`() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.jetbrains.dokka.PluginConfigurationImpl
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.junit.jupiter.api.Test
import utils.OnlyDescriptors
import utils.classSignature
import utils.findTestType
import kotlin.test.assertEquals
Expand Down Expand Up @@ -128,6 +129,7 @@ class ContentForInheritorsTest : BaseAbstractTest() {
}
}

@OnlyDescriptors("Order of inheritors is different in K2")
@Test
fun `interface with few inheritors has table in description`() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `deprecated with multiple links inside`() {
testInline(
Expand Down Expand Up @@ -346,6 +347,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `deprecated with an multiple inline links`() {
testInline(
Expand Down Expand Up @@ -410,6 +412,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `multiline throws with comment`() {
testInline(
Expand Down Expand Up @@ -473,6 +476,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@OnlyDescriptors("Fixed in 1.9.20 (IMPORT STAR)")
@Test
fun `multiline kotlin throws with comment`() {
testInline(
Expand Down Expand Up @@ -590,6 +594,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `multiline throws where exception is not in the same line as description`() {
testInline(
Expand Down Expand Up @@ -673,6 +678,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}


@JavaCode
@Test
fun `documentation splitted in 2 using enters`() {
testInline(
Expand Down Expand Up @@ -718,6 +724,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `multiline return tag with param`() {
testInline(
Expand Down Expand Up @@ -783,6 +790,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@UsingJDK
@Test
fun `return tag in kotlin`() {
testInline(
Expand Down Expand Up @@ -830,6 +838,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun `list with links and description`() {
testInline(
Expand Down Expand Up @@ -1476,6 +1485,7 @@ class ContentForParamsTest : BaseAbstractTest() {
}
}

@JavaCode
@Test
fun javaDocCommentWithDocumentedParameters() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class ContentForSeeAlsoTest : BaseAbstractTest() {
}
}

@OnlyDescriptors("No link for `abc` in K1")
@Test
fun `undocumented seealso with reference to parameter for class`() {
testInline(
Expand Down Expand Up @@ -201,7 +202,7 @@ class ContentForSeeAlsoTest : BaseAbstractTest() {
header(4) { +"See also" }
table {
group {
+"abc"
+"abc" // link { +"abc" }
}
}
}
Expand Down Expand Up @@ -751,6 +752,7 @@ class ContentForSeeAlsoTest : BaseAbstractTest() {
}
}

@OnlyDescriptorsMPP
@Test
fun `multiplatform class with seealso in few platforms`() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.pages.BasicTabbedContentType
import org.jetbrains.dokka.pages.ContentPage
import org.junit.jupiter.api.Test
import utils.OnlyDescriptors

class ConstructorsSignaturesTest : BaseAbstractTest() {
private val testConfiguration = dokkaConfiguration {
Expand Down Expand Up @@ -157,6 +158,7 @@ class ConstructorsSignaturesTest : BaseAbstractTest() {
}
}

@OnlyDescriptors("Order of constructors is different in K2")
@Test
fun `class with a parameterless secondary constructor`() {
testInline(
Expand Down Expand Up @@ -227,6 +229,7 @@ class ConstructorsSignaturesTest : BaseAbstractTest() {
}


@OnlyDescriptors("Order of constructors is different in K2")
@Test
fun `class with a few documented constructors`() {
testInline(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import testApi.testRunner.dokkaConfiguration
import utils.JavaCode
import kotlin.test.assertEquals

@JavaCode
class JavaVisibilityFilterTest : BaseAbstractTest() {

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.jetbrains.dokka.model.GenericTypeConstructor
import org.jetbrains.dokka.model.Invariance
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import utils.OnlyDescriptors

class KotlinArrayDocumentableReplacerTest : BaseAbstractTest() {
private val configuration = dokkaConfiguration {
Expand Down Expand Up @@ -157,6 +158,8 @@ class KotlinArrayDocumentableReplacerTest : BaseAbstractTest() {
}
}
}

@OnlyDescriptors("Fix module.contentScope in new Standalone API") // TODO fix module.contentScope [getKtModuleForKtElement]
@Test
fun `no jvm source set`() {
val configurationWithNoJVM = dokkaConfiguration {
Expand Down
Loading

0 comments on commit 0e00edc

Please sign in to comment.