Skip to content

Commit

Permalink
[K2] Support kotlin-as-java and javadoc plugins and update version of…
Browse files Browse the repository at this point in the history
… Analysis API (#3227)

* Implement InheritanceBuilder and for symbols

* Enable tests for as-java and javadoc plugins and fix some

* Update the version of Analysis API and enable test

* Use assert from kotlin.test

* Rename `descriptorInheritanceBuilder`

* Fix after rebasing

* Mute test `two classes from different packages`
  • Loading branch information
vmishenev committed Oct 26, 2023
1 parent 3be4dd9 commit 9b07435
Show file tree
Hide file tree
Showing 20 changed files with 308 additions and 60 deletions.
Expand Up @@ -17,4 +17,4 @@ class Greeter(val name: String) {

fun main(args: Array<String>) {
Greeter(args[0]).greet()
}
}
15 changes: 15 additions & 0 deletions plugins/base/src/test/kotlin/model/ClassesTest.kt
Expand Up @@ -126,6 +126,21 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class
type.name equals "Unit"
}
}

with((this.companion).cast<DObject>()) {
name equals "Companion"
children counts 5

with((this / "x").cast<DProperty>()) {
name equals "x"
}

with((this / "foo").cast<DFunction>()) {
name equals "foo"
parameters counts 0
type.name equals "Unit"
}
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion plugins/javadoc/build.gradle.kts
Expand Up @@ -7,6 +7,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 @@ -22,7 +23,11 @@ dependencies {
implementation(libs.kotlinx.coroutines.core)

testImplementation(kotlin("test"))
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.testApi)
testImplementation(libs.jsoup)
}
Expand Down
Expand Up @@ -28,6 +28,7 @@ internal abstract class AbstractJavadocTemplateMapTest : BaseAbstractTest() {
DokkaConfiguration.ExternalDocumentationLink.jdk(8),
DokkaConfiguration.ExternalDocumentationLink.kotlinStdlib()
)
classpath = listOfNotNull(jvmStdlibPath)
}
}
}
Expand Down
Expand Up @@ -8,6 +8,7 @@ import org.jsoup.Jsoup
import utils.TestOutputWriterPlugin
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() {

Expand All @@ -16,6 +17,7 @@ internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() {
sourceSets {
sourceSet {
sourceRoots = listOf("src/main/kotlin")
classpath = listOfNotNull(jvmStdlibPath)
}
}
}
Expand Down Expand Up @@ -54,13 +56,20 @@ internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() {
.select("code")
.map { it.text() }
.toSet()

assertEquals(setOf(
"getIssuesFetched()",
"setIssuesFetched(Integer issuesFetched)",
"isFoo()",
"setFoo(String isFoo)",
), props)
// In K2 name of accessors parameter is `value`
assertTrue(
setOf(
"getIssuesFetched()",
"setIssuesFetched(Integer issuesFetched)",
"isFoo()",
"setFoo(String isFoo)",
) == props || setOf(
"getIssuesFetched()",
"setIssuesFetched(Integer value)",
"isFoo()",
"setFoo(String value)",
) == props
)

val descriptionLinks = html
.select("div.description")
Expand Down
Expand Up @@ -8,11 +8,13 @@ import org.jetbrains.dokka.javadoc.pages.AllClassesPage
import org.jetbrains.dokka.javadoc.pages.LinkJavadocListEntry
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.pages.ContentKind
import org.junit.jupiter.api.Tag
import kotlin.test.Test
import kotlin.test.assertEquals

internal class JavadocAllClassesTemplateMapTest : AbstractJavadocTemplateMapTest() {
@Test
@Tag("onlyDescriptors") // https://github.com/Kotlin/dokka/issues/3250
fun `two classes from different packages`() {
dualTestTemplateMapInline(
"""
Expand Down
Expand Up @@ -7,6 +7,7 @@ package org.jetbrains.dokka.javadoc
import org.jetbrains.dokka.javadoc.pages.IndexPage
import org.jetbrains.dokka.javadoc.renderer.TemplateMap
import org.jetbrains.dokka.links.DRI
import org.junit.jupiter.api.Tag
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
Expand Down Expand Up @@ -76,7 +77,21 @@ internal class JavadocIndexTest : AbstractJavadocTemplateMapTest() {
AnnotationTarget.ANNOTATION_CLASS::class.java.methods.any { it.name == "describeConstable" }

testIndexPages(commonTestQuery) { indexPages ->
assertEquals(if (hasAdditionalFunction()) 33 else 32, indexPages.sumBy { it.elements.size })
assertEquals("A-index: a, A\n" +
"B-index: b\n" +
"C-index: c, ClassA, ClassB, ClassC, ClassC.InnerClass, ClassCEnum, compareTo\n" +
"D-index: d, D\n" +
"E-index: e, E, equals, equals\n" +
"F-index: f\n" +
"G-index: g, getDeclaringClass, getEntries, getName, getOrdinal\n" +
"H-index: h, hashCode, hashCode\n" +
"J-index: j\n" +
"K-index: k\n" +
"P-index: package0, package1\n" +
"T-index: toString, toString\n" +
"V-index: valueOf, values",
indexPages.joinToString("\n") { it.title + ": " + it.elements.joinToString { it.getId() } })
assertEquals(if (hasAdditionalFunction()) 34 else 33, indexPages.sumBy { it.elements.size })
}
}

Expand Down
Expand Up @@ -247,6 +247,7 @@ class JavadocLocationTest : BaseAbstractTest() {
DokkaConfiguration.ExternalDocumentationLink.kotlinStdlib()
)
analysisPlatform = "jvm"
classpath = listOfNotNull(jvmStdlibPath)
}
}
}
Expand Down
Expand Up @@ -18,15 +18,15 @@ class MultiplatformConfiguredCheckerTest : BaseAbstractTest() {
format = "javadoc"
sourceSets {
sourceSet {
sourceRoots = listOf("src")
sourceRoots = listOf("src/jvm")
analysisPlatform = "jvm"
externalDocumentationLinks = listOf(
ExternalDocumentationLink("https://docs.oracle.com/javase/8/docs/api/"),
ExternalDocumentationLink("https://kotlinlang.org/api/latest/jvm/stdlib/")
)
}
sourceSet {
sourceRoots = listOf("src")
sourceRoots = listOf("src/js")
analysisPlatform = "js"
externalDocumentationLinks = listOf(
ExternalDocumentationLink("https://docs.oracle.com/javase/8/docs/api/"),
Expand Down Expand Up @@ -54,7 +54,9 @@ class MultiplatformConfiguredCheckerTest : BaseAbstractTest() {
fun `mpp config should fail for javadoc`() {
testInline(
"""
|/src/main/kotlin/example/Test.kt
|/src/jvm/kotlin/example/Test.kt
|class Test
|/src/js/kotlin/example/Test.kt
|class Test
""".trimMargin(), mppConfig
) {
Expand Down
7 changes: 6 additions & 1 deletion plugins/kotlin-as-java/build.gradle.kts
Expand Up @@ -7,6 +7,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 @@ -20,7 +21,11 @@ dependencies {
testImplementation(kotlin("test"))
testImplementation(libs.jsoup)
testImplementation(projects.plugins.base)
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)
}
Expand Down
Expand Up @@ -377,6 +377,7 @@ class KotlinAsJavaPluginTest : BaseAbstractTest() {
DokkaConfiguration.ExternalDocumentationLink.jdk(8),
stdlibExternalDocumentationLink
)
classpath = listOfNotNull(jvmStdlibPath)
}
}
}
Expand Down
Expand Up @@ -23,6 +23,7 @@ class KotlinAsJavaSignatureTest : BaseAbstractTest() {
DokkaConfiguration.ExternalDocumentationLink.jdk(8),
stdlibExternalDocumentationLink
)
classpath = listOfNotNull(jvmStdlibPath)
}
}
}
Expand Down
Expand Up @@ -9,5 +9,21 @@ import org.jetbrains.dokka.links.DRI

@InternalDokkaApi
public interface KotlinToJavaService {
/**
* E.g.
* kotlin.Throwable -> java.lang.Throwable
* kotlin.Int -> java.lang.Integer
* kotlin.Int.Companion -> kotlin.jvm.internal.IntCompanionObject
* kotlin.Nothing -> java.lang.Void
* kotlin.IntArray -> null
* kotlin.Function3 -> kotlin.jvm.functions.Function3
* kotlin.coroutines.SuspendFunction3 -> kotlin.jvm.functions.Function4
* kotlin.Function42 -> kotlin.jvm.functions.FunctionN
* kotlin.coroutines.SuspendFunction42 -> kotlin.jvm.functions.FunctionN
* kotlin.reflect.KFunction3 -> kotlin.reflect.KFunction
* kotlin.reflect.KSuspendFunction3 -> kotlin.reflect.KFunction
* kotlin.reflect.KFunction42 -> kotlin.reflect.KFunction
* kotlin.reflect.KSuspendFunction42 -> kotlin.reflect.KFunction
*/
public fun findAsJava(kotlinDri: DRI): DRI?
}
Expand Up @@ -92,6 +92,7 @@ public class SymbolsAnalysisPlugin : DokkaPlugin() {
internal val symbolAnalyzerImpl by extending {
plugin<InternalKotlinAnalysisPlugin>().documentableSourceLanguageParser providing { KotlinDocumentableSourceLanguageParser() }
}

internal val symbolFullClassHierarchyBuilder by extending {
plugin<InternalKotlinAnalysisPlugin>().fullClassHierarchyBuilder providing ::SymbolFullClassHierarchyBuilder
}
Expand All @@ -104,14 +105,14 @@ public class SymbolsAnalysisPlugin : DokkaPlugin() {
plugin<InternalKotlinAnalysisPlugin>().moduleAndPackageDocumentationReader providing ::ModuleAndPackageDocumentationReader
}

/* internal val kotlinToJavaMapper by extending {
plugin<InternalKotlinAnalysisPlugin>().kotlinToJavaService providing { DescriptorKotlinToJavaMapper() }
internal val kotlinToJavaMapper by extending {
plugin<InternalKotlinAnalysisPlugin>().kotlinToJavaService providing { SymbolKotlinToJavaMapper() }
}

intern val descriptorInheritanceBuilder by extending {
plugin<InternalKotlinAnalysisPlugin>().inheritanceBuilder providing { DescriptorInheritanceBuilder() }
internal val symbolInheritanceBuilder by extending {
plugin<InternalKotlinAnalysisPlugin>().inheritanceBuilder providing ::SymbolInheritanceBuilder
}
*/

internal val symbolExternalDocumentablesProvider by extending {
plugin<InternalKotlinAnalysisPlugin>().externalDocumentablesProvider providing ::SymbolExternalDocumentablesProvider
}
Expand Down
Expand Up @@ -5,6 +5,7 @@
package org.jetbrains.dokka.analysis.kotlin.symbols.services

import com.intellij.psi.PsiClass
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource
import org.jetbrains.dokka.analysis.java.util.from
import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getDRIFromClassLike
Expand All @@ -17,14 +18,16 @@ import org.jetbrains.dokka.analysis.kotlin.internal.ClassHierarchy
import org.jetbrains.dokka.analysis.kotlin.internal.FullClassHierarchyBuilder
import org.jetbrains.dokka.analysis.kotlin.internal.Supertypes
import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin
import org.jetbrains.dokka.analysis.kotlin.symbols.translators.AnnotationTranslator
import org.jetbrains.dokka.analysis.kotlin.symbols.translators.TypeTranslator
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.querySingle
import org.jetbrains.kotlin.psi.KtClassOrObject
import java.util.concurrent.ConcurrentHashMap


internal class SymbolFullClassHierarchyBuilder(val context: DokkaContext) : FullClassHierarchyBuilder {
internal class SymbolFullClassHierarchyBuilder(context: DokkaContext) : FullClassHierarchyBuilder {
private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis }

override suspend fun build(module: DModule): ClassHierarchy {
Expand All @@ -38,14 +41,13 @@ internal class SymbolFullClassHierarchyBuilder(val context: DokkaContext) : Full
supersMap: MutableMap<DRI, Supertypes>
) {
val (dri, kotlinType) = driWithKType
val supertypes = kotlinType.getDirectSuperTypes().filterNot { it.isAny }
val supertypesDriWithKType = supertypes.mapNotNull { supertype ->
supertype.expandedClassSymbol?.let {
getDRIFromClassLike(it) to supertype
}
}

if (supersMap[dri] == null) {
val supertypes = kotlinType.getDirectSuperTypes(shouldApproximate = true).filterNot { it.isAny }
val supertypesDriWithKType = supertypes.mapNotNull { supertype ->
supertype.expandedClassSymbol?.let {
getDRIFromClassLike(it) to supertype
}
}
supersMap[dri] = supertypesDriWithKType.map { it.first }
supertypesDriWithKType.forEach { collectSupertypesFromKtType(it, supersMap) }
}
Expand Down Expand Up @@ -92,4 +94,55 @@ internal class SymbolFullClassHierarchyBuilder(val context: DokkaContext) : Full
}
}

internal class SuperclassesWithKind(
val typeConstructorWithKind: TypeConstructorWithKind,
val superclasses: List<TypeConstructorWithKind>
)

/**
* Currently, it works only for Symbols
*/
internal fun collectKotlinSupertypesWithKind(
documentable: Iterable<Documentable>,
sourceSet: DokkaConfiguration.DokkaSourceSet
): Map<DRI, SuperclassesWithKind> {
val typeTranslator = TypeTranslator(sourceSet, AnnotationTranslator())
val hierarchy = mutableMapOf<DRI, SuperclassesWithKind>()

analyze(kotlinAnalysis.getModule(sourceSet)) {
documentable.filterIsInstance<DClasslike>().forEach {
val source = it.sources[sourceSet]
if (source is KtPsiDocumentableSource) {
(source.psi as? KtClassOrObject)?.let { psi ->
val type = psi.getNamedClassOrObjectSymbol()?.buildSelfClassType() ?: return@analyze
collectSupertypesWithKindFromKtType(typeTranslator, with(typeTranslator) {
toTypeConstructorWithKindFrom(type)
} to type, hierarchy)
}
} // else if (source is PsiDocumentableSource) TODO val psi = source.psi as? PsiClass
}
}
return hierarchy
}

private fun KtAnalysisSession.collectSupertypesWithKindFromKtType(
typeTranslator: TypeTranslator,
typeConstructorWithKindWithKType: Pair<TypeConstructorWithKind, KtType>,
supersMap: MutableMap<DRI, SuperclassesWithKind>
) {
val (typeConstructorWithKind, kotlinType) = typeConstructorWithKindWithKType

if (supersMap[typeConstructorWithKind.typeConstructor.dri] == null) {
val supertypes = kotlinType.getDirectSuperTypes(shouldApproximate = true).filterNot { it.isAny }

val supertypesDriWithKType = supertypes.map { supertype ->
with(typeTranslator) {
toTypeConstructorWithKindFrom(supertype)
} to supertype
}
supersMap[typeConstructorWithKind.typeConstructor.dri] =
SuperclassesWithKind(typeConstructorWithKind, supertypesDriWithKType.map { it.first })
supertypesDriWithKType.forEach { collectSupertypesWithKindFromKtType(typeTranslator, it, supersMap) }
}
}
}

0 comments on commit 9b07435

Please sign in to comment.