diff --git a/analysis/java-analysis-psi/api/java-analysis-psi.api b/analysis/java-analysis-psi/api/java-analysis-psi.api new file mode 100644 index 00000000000..aab52cd30f8 --- /dev/null +++ b/analysis/java-analysis-psi/api/java-analysis-psi.api @@ -0,0 +1,148 @@ +public final class org/jetbrains/dokka/analysis/java/AuthorJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field INSTANCE Lorg/jetbrains/dokka/analysis/java/AuthorJavadocTag; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/BreakingAbstractionKotlinLightMethodChecker { + public abstract fun isLightAnnotation (Lcom/intellij/psi/PsiAnnotation;)Z + public abstract fun isLightAnnotationAttribute (Lcom/intellij/lang/jvm/annotation/JvmAnnotationAttribute;)Z +} + +public final class org/jetbrains/dokka/analysis/java/DeprecatedJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field INSTANCE Lorg/jetbrains/dokka/analysis/java/DeprecatedJavadocTag; +} + +public final class org/jetbrains/dokka/analysis/java/DescriptionJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field INSTANCE Lorg/jetbrains/dokka/analysis/java/DescriptionJavadocTag; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/DocComment { + public abstract fun hasTag (Lorg/jetbrains/dokka/analysis/java/JavadocTag;)Z + public abstract fun resolveTag (Lorg/jetbrains/dokka/analysis/java/JavadocTag;)Ljava/util/List; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/DocCommentCreator { + public abstract fun create (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/DocComment; +} + +public final class org/jetbrains/dokka/analysis/java/DocCommentFactory { + public fun (Ljava/util/List;)V + public final fun fromElement (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/DocComment; +} + +public final class org/jetbrains/dokka/analysis/java/DocCommentFinder { + public fun (Lorg/jetbrains/dokka/utilities/DokkaLogger;Lorg/jetbrains/dokka/analysis/java/DocCommentFactory;)V + public final fun findClosestToElement (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/DocComment; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/DocCommentParser { + public abstract fun canParse (Lorg/jetbrains/dokka/analysis/java/DocComment;)Z + public abstract fun parse (Lorg/jetbrains/dokka/analysis/java/DocComment;Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/DocumentationContent { + public abstract fun getTag ()Lorg/jetbrains/dokka/analysis/java/JavadocTag; + public abstract fun resolveSiblings ()Ljava/util/List; +} + +public final class org/jetbrains/dokka/analysis/java/ExceptionJavadocTag : org/jetbrains/dokka/analysis/java/ThrowingExceptionJavadocTag { + public static final field Companion Lorg/jetbrains/dokka/analysis/java/ExceptionJavadocTag$Companion; + public static final field name Ljava/lang/String; + public fun (Ljava/lang/String;)V +} + +public final class org/jetbrains/dokka/analysis/java/ExceptionJavadocTag$Companion { +} + +public final class org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { + public fun ()V + public final fun getDocCommentCreators ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getDocCommentFinder ()Lorg/jetbrains/dokka/analysis/java/DocCommentFinder; + public final fun getDocCommentParsers ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getInheritDocTagContentProviders ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getKotlinLightMethodChecker ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getProjectProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getSourceRootsExtractor ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; +} + +public abstract class org/jetbrains/dokka/analysis/java/JavadocTag { + public synthetic fun (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getName ()Ljava/lang/String; +} + +public final class org/jetbrains/dokka/analysis/java/ParamJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field Companion Lorg/jetbrains/dokka/analysis/java/ParamJavadocTag$Companion; + public static final field name Ljava/lang/String; + public fun (Lcom/intellij/psi/PsiMethod;Ljava/lang/String;I)V + public final fun getMethod ()Lcom/intellij/psi/PsiMethod; + public final fun getParamIndex ()I + public final fun getParamName ()Ljava/lang/String; +} + +public final class org/jetbrains/dokka/analysis/java/ParamJavadocTag$Companion { +} + +public abstract interface class org/jetbrains/dokka/analysis/java/ProjectProvider { + public abstract fun getProject (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;)Lcom/intellij/openapi/project/Project; +} + +public final class org/jetbrains/dokka/analysis/java/ReturnJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field INSTANCE Lorg/jetbrains/dokka/analysis/java/ReturnJavadocTag; +} + +public final class org/jetbrains/dokka/analysis/java/SeeJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field Companion Lorg/jetbrains/dokka/analysis/java/SeeJavadocTag$Companion; + public static final field name Ljava/lang/String; + public fun (Ljava/lang/String;)V + public final fun getQualifiedReference ()Ljava/lang/String; +} + +public final class org/jetbrains/dokka/analysis/java/SeeJavadocTag$Companion { +} + +public final class org/jetbrains/dokka/analysis/java/SinceJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public static final field INSTANCE Lorg/jetbrains/dokka/analysis/java/SinceJavadocTag; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/SourceRootsExtractor { + public abstract fun extract (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;)Ljava/util/List; +} + +public abstract class org/jetbrains/dokka/analysis/java/ThrowingExceptionJavadocTag : org/jetbrains/dokka/analysis/java/JavadocTag { + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getExceptionQualifiedName ()Ljava/lang/String; +} + +public final class org/jetbrains/dokka/analysis/java/ThrowsJavadocTag : org/jetbrains/dokka/analysis/java/ThrowingExceptionJavadocTag { + public static final field Companion Lorg/jetbrains/dokka/analysis/java/ThrowsJavadocTag$Companion; + public static final field name Ljava/lang/String; + public fun (Ljava/lang/String;)V +} + +public final class org/jetbrains/dokka/analysis/java/ThrowsJavadocTag$Companion { +} + +public final class org/jetbrains/dokka/analysis/java/doctag/DocTagParserContext { + public fun ()V + public final fun getDocumentationNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocumentationNode; + public final fun getDri (Ljava/lang/String;)Lorg/jetbrains/dokka/links/DRI; + public final fun store (Lorg/jetbrains/dokka/links/DRI;)Ljava/lang/String; + public final fun store (Lorg/jetbrains/dokka/model/doc/DocumentationNode;)Ljava/lang/String; +} + +public abstract interface class org/jetbrains/dokka/analysis/java/doctag/InheritDocTagContentProvider { + public abstract fun canConvert (Lorg/jetbrains/dokka/analysis/java/DocumentationContent;)Z + public abstract fun convertToHtml (Lorg/jetbrains/dokka/analysis/java/DocumentationContent;Lorg/jetbrains/dokka/analysis/java/doctag/DocTagParserContext;)Ljava/lang/String; +} + +public final class org/jetbrains/dokka/analysis/java/parsers/JavadocParser : org/jetbrains/dokka/analysis/java/parsers/JavaDocumentationParser { + public fun (Ljava/util/List;Lorg/jetbrains/dokka/analysis/java/DocCommentFinder;)V + public fun parseDocumentation (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode; +} + +public final class org/jetbrains/dokka/analysis/java/util/PsiDocumentableSource : org/jetbrains/dokka/model/DocumentableSource { + public fun (Lcom/intellij/psi/PsiNamedElement;)V + public fun getLineNumber ()Ljava/lang/Integer; + public fun getPath ()Ljava/lang/String; + public final fun getPsi ()Lcom/intellij/psi/PsiNamedElement; +} + diff --git a/analysis/java-analysis-psi/build.gradle.kts b/analysis/java-analysis-psi/build.gradle.kts new file mode 100644 index 00000000000..90877952196 --- /dev/null +++ b/analysis/java-analysis-psi/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id("org.jetbrains.conventions.kotlin-jvm") +} + +dependencies { + // TODO [beresnev] extract into versions.toml + val idea_version = "203.8084.24" // must match the version used in kotlin + + compileOnly(projects.core) + + api("com.jetbrains.intellij.java:java-psi:$idea_version") + + implementation(projects.analysis.markdown) + + implementation("com.jetbrains.intellij.platform:util:$idea_version") + implementation("com.jetbrains.intellij.java:java-psi-impl:$idea_version") + implementation("com.jetbrains.intellij.platform:util-rt:$idea_version") + implementation("com.jetbrains.intellij.platform:jps-model-impl:$idea_version") + + implementation(libs.kotlinx.coroutines.core) + implementation(libs.jsoup) +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt new file mode 100644 index 00000000000..1695e7f09ee --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt @@ -0,0 +1,82 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.PsiKeyword +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiModifierListOwner +import kotlinx.coroutines.coroutineScope +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.analysis.java.parsers.JavaPsiDocCommentParser +import org.jetbrains.dokka.analysis.java.parsers.JavadocParser +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.JavaVisibility +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTranslator +import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.dokka.utilities.parallelMapNotNull + +internal class DefaultPsiToDocumentableTranslator : AsyncSourceToDocumentableTranslator { + + override suspend fun invokeSuspending(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { + return coroutineScope { + val projectProvider = context.plugin().querySingle { projectProvider } + val project = projectProvider.getProject(sourceSet, context) + + val sourceRootsExtractor = context.plugin().querySingle { sourceRootsExtractor } + val sourceRoots = sourceRootsExtractor.extract(sourceSet, context) + + val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file") + + val psiFiles = sourceRoots.parallelMap { sourceRoot -> + sourceRoot.absoluteFile.walkTopDown().mapNotNull { + localFileSystem.findFileByPath(it.path)?.let { vFile -> + PsiManager.getInstance(project).findFile(vFile) as? PsiJavaFile + } + }.toList() + }.flatten() + + val docParser = createPsiParser(sourceSet, context) + + DModule( + name = context.configuration.moduleName, + packages = psiFiles.parallelMapNotNull { it }.groupBy { it.packageName }.toList() + .parallelMap { (packageName: String, psiFiles: List) -> + docParser.parsePackage(packageName, psiFiles) + }, + documentation = emptyMap(), + expectPresentInSet = null, + sourceSets = setOf(sourceSet) + ) + } + } + + private fun createPsiParser(sourceSet: DokkaSourceSet, context: DokkaContext): DokkaPsiParser { + val projectProvider = context.plugin().querySingle { projectProvider } + val docCommentParsers = context.plugin().query { docCommentParsers } + return DokkaPsiParser( + sourceSetData = sourceSet, + project = projectProvider.getProject(sourceSet, context), + logger = context.logger, + javadocParser = JavadocParser( + docCommentParsers = docCommentParsers, + docCommentFinder = context.plugin().docCommentFinder + ), + javaPsiDocCommentParser = docCommentParsers.single { it is JavaPsiDocCommentParser } as JavaPsiDocCommentParser, + lightMethodChecker = context.plugin().querySingle { kotlinLightMethodChecker } + ) + } +} + +internal fun PsiModifierListOwner.getVisibility() = modifierList?.let { + val ml = it.children.toList() + when { + ml.any { it.text == PsiKeyword.PUBLIC } || it.hasModifierProperty("public") -> JavaVisibility.Public + ml.any { it.text == PsiKeyword.PROTECTED } || it.hasModifierProperty("protected") -> JavaVisibility.Protected + ml.any { it.text == PsiKeyword.PRIVATE } || it.hasModifierProperty("private") -> JavaVisibility.Private + else -> JavaVisibility.Default + } +} ?: JavaVisibility.Default diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocComment.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocComment.kt new file mode 100644 index 00000000000..4f4a5844ac6 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocComment.kt @@ -0,0 +1,13 @@ +package org.jetbrains.dokka.analysis.java + +import org.jetbrains.dokka.InternalDokkaApi + +/** + * MUST override equals and hashcode + */ +@InternalDokkaApi +interface DocComment { + fun hasTag(tag: JavadocTag): Boolean + + fun resolveTag(tag: JavadocTag): List +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentCreator.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentCreator.kt new file mode 100644 index 00000000000..cac7e7bb1bb --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentCreator.kt @@ -0,0 +1,9 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.dokka.InternalDokkaApi + +@InternalDokkaApi +interface DocCommentCreator { + fun create(element: PsiNamedElement): DocComment? +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFactory.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFactory.kt new file mode 100644 index 00000000000..3566a4ce8db --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFactory.kt @@ -0,0 +1,20 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.dokka.InternalDokkaApi + +@InternalDokkaApi +class DocCommentFactory( + private val docCommentCreators: List +) { + fun fromElement(element: PsiNamedElement): DocComment? { + docCommentCreators.forEach { creator -> + val comment = creator.create(element) + if (comment != null) { + return comment + } + } + return null + } +} + diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFinder.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFinder.kt new file mode 100644 index 00000000000..2ed3c448f96 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentFinder.kt @@ -0,0 +1,64 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.javadoc.PsiDocComment +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.analysis.java.util.from +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.utilities.DokkaLogger + +@InternalDokkaApi +class DocCommentFinder( + private val logger: DokkaLogger, + private val docCommentFactory: DocCommentFactory, +) { + fun findClosestToElement(element: PsiNamedElement): DocComment? { + val docComment = docCommentFactory.fromElement(element) + if (docComment != null) { + return docComment + } + + return if (element is PsiMethod) { + findClosestToMethod(element) + } else { + element.children + .filterIsInstance() + .firstOrNull() + ?.let { JavaDocComment(it) } + } + } + + private fun findClosestToMethod(method: PsiMethod): DocComment? { + val superMethods = method.findSuperMethods() + if (superMethods.isEmpty()) return null + + if (superMethods.size == 1) { + return findClosestToElement(superMethods.single()) + } + + val superMethodDocumentation = superMethods.map { superMethod -> findClosestToElement(superMethod) }.distinct() + if (superMethodDocumentation.size == 1) { + return superMethodDocumentation.single() + } + + logger.debug( + "Conflicting documentation for ${DRI.from(method)}" + + "${superMethods.map { DRI.from(it) }}" + ) + + /* Prioritize super class over interface */ + val indexOfSuperClass = superMethods.indexOfFirst { superMethod -> + val parent = superMethod.parent + if (parent is PsiClass) !parent.isInterface + else false + } + + return if (indexOfSuperClass >= 0) { + superMethodDocumentation[indexOfSuperClass] + } else { + superMethodDocumentation.first() + } + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentParser.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentParser.kt new file mode 100644 index 00000000000..2f2158677eb --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocCommentParser.kt @@ -0,0 +1,11 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.model.doc.DocumentationNode + +@InternalDokkaApi +interface DocCommentParser { + fun canParse(docComment: DocComment): Boolean + fun parse(docComment: DocComment, context: PsiNamedElement): DocumentationNode +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocumentationContent.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocumentationContent.kt new file mode 100644 index 00000000000..78fc1c58ccd --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DocumentationContent.kt @@ -0,0 +1,10 @@ +package org.jetbrains.dokka.analysis.java + +import org.jetbrains.dokka.InternalDokkaApi + +@InternalDokkaApi +interface DocumentationContent { + val tag: JavadocTag + + fun resolveSiblings(): List +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DokkaPsiParser.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DokkaPsiParser.kt new file mode 100644 index 00000000000..2b12103add8 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DokkaPsiParser.kt @@ -0,0 +1,796 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute +import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue +import com.intellij.lang.jvm.annotation.JvmAnnotationConstantValue +import com.intellij.lang.jvm.annotation.JvmAnnotationEnumFieldValue +import com.intellij.lang.jvm.types.JvmReferenceType +import com.intellij.openapi.project.Project +import com.intellij.psi.* +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.analysis.java.parsers.JavaPsiDocCommentParser +import org.jetbrains.dokka.analysis.java.parsers.JavadocParser +import org.jetbrains.dokka.analysis.java.util.* +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.nextTarget +import org.jetbrains.dokka.links.withClass +import org.jetbrains.dokka.links.withEnumEntryExtra +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.AnnotationTarget +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.dokka.utilities.parallelForEach +import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.dokka.utilities.parallelMapNotNull + +internal class DokkaPsiParser( + private val sourceSetData: DokkaConfiguration.DokkaSourceSet, + private val project: Project, + private val logger: DokkaLogger, + private val javadocParser: JavadocParser, + private val javaPsiDocCommentParser: JavaPsiDocCommentParser, + private val lightMethodChecker: BreakingAbstractionKotlinLightMethodChecker, +) { + private val syntheticDocProvider = SyntheticElementDocumentationProvider(javaPsiDocCommentParser, project) + + private val cachedBounds = hashMapOf() + + private val PsiMethod.hash: Int + get() = "$returnType $name$parameterList".hashCode() + + private val PsiField.hash: Int + get() = "$type $name".hashCode() + + private val PsiClassType.shouldBeIgnored: Boolean + get() = isClass("java.lang.Enum") || isClass("java.lang.Object") + + private fun PsiClassType.isClass(qName: String): Boolean { + val shortName = qName.substringAfterLast('.') + if (className == shortName) { + val psiClass = resolve() + return psiClass?.qualifiedName == qName + } + return false + } + + private fun T.toSourceSetDependent() = mapOf(sourceSetData to this) + + suspend fun parsePackage(packageName: String, psiFiles: List): DPackage = coroutineScope { + val dri = DRI(packageName = packageName) + val packageInfo = psiFiles.singleOrNull { it.name == "package-info.java" } + val documentation = packageInfo?.let { + javadocParser.parseDocumentation(it).toSourceSetDependent() + }.orEmpty() + val annotations = packageInfo?.packageStatement?.annotationList?.annotations + + DPackage( + dri = dri, + functions = emptyList(), + properties = emptyList(), + classlikes = psiFiles.parallelMap { psiFile -> + coroutineScope { + psiFile.classes.asIterable().parallelMap { parseClasslike(it, dri) } + } + }.flatten(), + typealiases = emptyList(), + documentation = documentation, + expectPresentInSet = null, + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( + annotations?.toList().orEmpty().toListOfAnnotations().toSourceSetDependent().toAnnotations() + ) + ) + } + + private suspend fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = coroutineScope { + with(psi) { + val dri = parent.withClass(name.toString()) + val superMethodsKeys = hashSetOf() + val superMethods = mutableListOf>() + val superFieldsKeys = hashSetOf() + val superFields = mutableListOf>() + methods.asIterable().parallelForEach { superMethodsKeys.add(it.hash) } + + /** + * Caution! This method mutates + * - superMethodsKeys + * - superMethods + * - superFieldsKeys + * - superKeys + */ + /** + * Caution! This method mutates + * - superMethodsKeys + * - superMethods + * - superFieldsKeys + * - superKeys + */ + fun Array.getSuperTypesPsiClasses(): List> { + forEach { type -> + (type as? PsiClassType)?.resolve()?.let { + val definedAt = DRI.from(it) + it.methods.forEach { method -> + val hash = method.hash + if (!method.isConstructor && !superMethodsKeys.contains(hash) && + method.getVisibility() != JavaVisibility.Private + ) { + superMethodsKeys.add(hash) + superMethods.add(Pair(method, definedAt)) + } + } + it.fields.forEach { field -> + val hash = field.hash + if (!superFieldsKeys.contains(hash)) { + superFieldsKeys.add(hash) + superFields.add(Pair(field, definedAt)) + } + } + } + } + return filter { !it.shouldBeIgnored }.mapNotNull { supertypePsi -> + supertypePsi.resolve()?.let { supertypePsiClass -> + val javaClassKind = when { + supertypePsiClass.isInterface -> JavaClassKindTypes.INTERFACE + else -> JavaClassKindTypes.CLASS + } + supertypePsiClass to javaClassKind + } + } + } + + fun traversePsiClassForAncestorsAndInheritedMembers(psiClass: PsiClass): AncestryNode { + val (classes, interfaces) = psiClass.superTypes.getSuperTypesPsiClasses() + .partition { it.second == JavaClassKindTypes.CLASS } + + return AncestryNode( + typeConstructor = GenericTypeConstructor( + DRI.from(psiClass), + psiClass.typeParameters.map { typeParameter -> + TypeParameter( + dri = DRI.from(typeParameter), + name = typeParameter.name.orEmpty(), + extra = typeParameter.annotations() + ) + } + ), + superclass = classes.singleOrNull()?.first?.let(::traversePsiClassForAncestorsAndInheritedMembers), + interfaces = interfaces.map { traversePsiClassForAncestorsAndInheritedMembers(it.first) } + ) + } + + val ancestry: AncestryNode = traversePsiClassForAncestorsAndInheritedMembers(this) + + val (regularFunctions, accessors) = splitFunctionsAndAccessors(psi.fields, psi.methods) + val (regularSuperFunctions, superAccessors) = splitFunctionsAndAccessors( + fields = superFields.map { it.first }.toTypedArray(), + methods = superMethods.map { it.first }.toTypedArray() + ) + + val regularSuperFunctionsKeys = regularSuperFunctions.map { it.hash }.toSet() + val regularSuperFunctionsWithDRI = superMethods.filter { it.first.hash in regularSuperFunctionsKeys } + + val superAccessorsWithDRI = superAccessors.mapValues { (field, methods) -> + val containsJvmField = field.annotations.mapNotNull { it.toAnnotation() }.any { it.isJvmField() } + if (containsJvmField) { + emptyList() + } else { + methods.mapNotNull { method -> superMethods.find { it.first.hash == method.hash } } + } + } + + val overridden = regularFunctions.flatMap { it.findSuperMethods().toList() } + val documentation = javadocParser.parseDocumentation(this).toSourceSetDependent() + val allFunctions = async { + val parsedRegularFunctions = regularFunctions.parallelMapNotNull { + if (!it.isConstructor) parseFunction( + it, + parentDRI = dri + ) else null + } + val parsedSuperFunctions = regularSuperFunctionsWithDRI + .filter { it.first !in overridden } + .parallelMap { parseFunction(it.first, inheritedFrom = it.second) } + + parsedRegularFunctions + parsedSuperFunctions + } + val allFields = async { + val parsedFields = fields.toList().parallelMapNotNull { + parseField(it, accessors[it].orEmpty()) + } + val parsedSuperFields = superFields.parallelMapNotNull { (field, dri) -> + parseFieldWithInheritingAccessors( + field, + superAccessorsWithDRI[field].orEmpty(), + inheritedFrom = dri + ) + } + parsedFields + parsedSuperFields + } + val source = parseSources() + val classlikes = async { innerClasses.asIterable().parallelMap { parseClasslike(it, dri) } } + val visibility = getVisibility().toSourceSetDependent() + val ancestors = (listOfNotNull(ancestry.superclass?.let { + it.typeConstructor.let { typeConstructor -> + TypeConstructorWithKind( + typeConstructor, + JavaClassKindTypes.CLASS + ) + } + }) + ancestry.interfaces.map { + TypeConstructorWithKind( + it.typeConstructor, + JavaClassKindTypes.INTERFACE + ) + }).toSourceSetDependent() + val modifiers = getModifier().toSourceSetDependent() + val implementedInterfacesExtra = + ImplementedInterfaces(ancestry.allImplementedInterfaces().toSourceSetDependent()) + + when { + isAnnotationType -> + DAnnotation( + name = name.orEmpty(), + dri = dri, + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + constructors = parseConstructors(dri), + generics = mapTypeParameters(dri), + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( + implementedInterfacesExtra, + annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + + isEnum -> DEnum( + dri = dri, + name = name.orEmpty(), + entries = fields.filterIsInstance().map { entry -> + DEnumEntry( + dri = dri.withClass(entry.name).withEnumEntryExtra(), + name = entry.name, + documentation = javadocParser.parseDocumentation(entry).toSourceSetDependent(), + expectPresentInSet = null, + functions = emptyList(), + properties = emptyList(), + classlikes = emptyList(), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( + implementedInterfacesExtra, + annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + }, + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = fields.filter { it !is PsiEnumConstant } + .map { parseField(it, accessors[it].orEmpty()) }, + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + constructors = parseConstructors(dri), + supertypes = ancestors, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( + implementedInterfacesExtra, + annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + + isInterface -> DInterface( + dri = dri, + name = name.orEmpty(), + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + generics = mapTypeParameters(dri), + supertypes = ancestors, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( + implementedInterfacesExtra, + annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + + else -> DClass( + dri = dri, + name = name.orEmpty(), + constructors = parseConstructors(dri), + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + sources = source, + visibility = visibility, + companion = null, + generics = mapTypeParameters(dri), + supertypes = ancestors, + documentation = documentation, + expectPresentInSet = null, + modifier = modifiers, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( + implementedInterfacesExtra, + annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations(), + ancestry.exceptionInSupertypesOrNull() + ) + ) + } + } + } + + /* + * Parameter `parentDRI` required for substitute package name: + * in the case of synthetic constructor, it will return empty from [DRI.Companion.from]. + */ + private fun PsiClass.parseConstructors(parentDRI: DRI): List { + val constructors = when { + isAnnotationType || isInterface -> emptyArray() + isEnum -> this.constructors + else -> this.constructors.takeIf { it.isNotEmpty() } ?: arrayOf(createDefaultConstructor()) + } + return constructors.map { parseFunction(psi = it, isConstructor = true, parentDRI = parentDRI) } + } + + /** + * PSI doesn't return a default constructor if class doesn't contain an explicit one. + * This method create synthetic constructor + * Visibility modifier is preserved from the class. + */ + private fun PsiClass.createDefaultConstructor(): PsiMethod { + val psiElementFactory = JavaPsiFacade.getElementFactory(project) + val signature = when (val classVisibility = getVisibility()) { + JavaVisibility.Default -> name.orEmpty() + else -> "${classVisibility.name} $name" + } + return psiElementFactory.createConstructor(signature, this) + } + + private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? = + typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() } + ?.let { ExceptionInSupertypes(it.toSourceSetDependent()) } + + private fun parseFunction( + psi: PsiMethod, + isConstructor: Boolean = false, + inheritedFrom: DRI? = null, + parentDRI: DRI? = null, + ): DFunction { + val dri = parentDRI?.let { dri -> + DRI.from(psi).copy(packageName = dri.packageName, classNames = dri.classNames) + } ?: DRI.from(psi) + val docs = psi.getDocumentation() + return DFunction( + dri = dri, + name = psi.name, + isConstructor = isConstructor, + parameters = psi.parameterList.parameters.map { psiParameter -> + DParameter( + dri = dri.copy(target = dri.target.nextTarget()), + name = psiParameter.name, + documentation = DocumentationNode( + listOfNotNull(docs.firstChildOfTypeOrNull { + it.name == psiParameter.name + }) + ).toSourceSetDependent(), + expectPresentInSet = null, + type = getBound(psiParameter.type), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( + psiParameter.annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + }, + documentation = docs.toSourceSetDependent(), + expectPresentInSet = null, + sources = psi.parseSources(), + visibility = psi.getVisibility().toSourceSetDependent(), + type = psi.returnType?.let { getBound(type = it) } ?: Void, + generics = psi.mapTypeParameters(dri), + receiver = null, + modifier = psi.getModifier().toSourceSetDependent(), + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = psi.additionalExtras().let { + PropertyContainer.withAll( + inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, + it.toSourceSetDependent().toAdditionalModifiers(), + (psi.annotations.toList() + .toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() + .toAnnotations(), + ObviousMember.takeIf { psi.isObvious(inheritedFrom) }, + psi.throwsList.toDriList().takeIf { it.isNotEmpty() } + ?.let { CheckedExceptions(it.toSourceSetDependent()) } + ) + } + ) + } + + private fun PsiNamedElement.parseSources(): SourceSetDependent { + return when { + // `isPhysical` detects the virtual declarations without real sources. + // Otherwise, `PsiDocumentableSource` initialization will fail: non-physical declarations doesn't have `virtualFile`. + // This check protects from accidentally requesting sources for synthetic / virtual declarations. + isPhysical -> PsiDocumentableSource(this).toSourceSetDependent() + else -> emptyMap() + } + } + + private fun PsiMethod.getDocumentation(): DocumentationNode = + this.takeIf { it is SyntheticElement }?.let { syntheticDocProvider.getDocumentation(it) } + ?: javadocParser.parseDocumentation(this) + + private fun PsiMethod.isObvious(inheritedFrom: DRI? = null): Boolean { + return (this is SyntheticElement && !syntheticDocProvider.isDocumented(this)) + || inheritedFrom?.isObvious() == true + } + + private fun DRI.isObvious(): Boolean { + return packageName == "java.lang" && (classNames == "Object" || classNames == "Enum") + } + + private fun PsiReferenceList.toDriList() = referenceElements.mapNotNull { it?.resolve()?.let { DRI.from(it) } } + + private fun PsiModifierListOwner.additionalExtras() = listOfNotNull( + ExtraModifiers.JavaOnlyModifiers.Static.takeIf { hasModifier(JvmModifier.STATIC) }, + ExtraModifiers.JavaOnlyModifiers.Native.takeIf { hasModifier(JvmModifier.NATIVE) }, + ExtraModifiers.JavaOnlyModifiers.Synchronized.takeIf { hasModifier(JvmModifier.SYNCHRONIZED) }, + ExtraModifiers.JavaOnlyModifiers.StrictFP.takeIf { hasModifier(JvmModifier.STRICTFP) }, + ExtraModifiers.JavaOnlyModifiers.Transient.takeIf { hasModifier(JvmModifier.TRANSIENT) }, + ExtraModifiers.JavaOnlyModifiers.Volatile.takeIf { hasModifier(JvmModifier.VOLATILE) }, + ExtraModifiers.JavaOnlyModifiers.Transitive.takeIf { hasModifier(JvmModifier.TRANSITIVE) } + ).toSet() + + private fun Set.toListOfAnnotations() = map { + if (it !is ExtraModifiers.JavaOnlyModifiers.Static) + Annotations.Annotation(DRI("kotlin.jvm", it.name.toLowerCase().capitalize()), emptyMap()) + else + Annotations.Annotation(DRI("kotlin.jvm", "JvmStatic"), emptyMap()) + } + + /** + * Workaround for getting JvmField Kotlin annotation in PSIs + */ + private fun Collection.findJvmFieldAnnotation(): Annotations.Annotation? { + val anyJvmFieldAnnotation = this.any { + it.qualifiedName == "$JVM_FIELD_PACKAGE_NAME.$JVM_FIELD_CLASS_NAMES" + } + return if (anyJvmFieldAnnotation) { + Annotations.Annotation(DRI(JVM_FIELD_PACKAGE_NAME, JVM_FIELD_CLASS_NAMES), emptyMap()) + } else { + null + } + } + + private fun PsiTypeParameter.annotations(): PropertyContainer = this.annotations.toList().toListOfAnnotations().annotations() + private fun PsiType.annotations(): PropertyContainer = this.annotations.toList().toListOfAnnotations().annotations() + + private fun List.annotations(): PropertyContainer = + this.takeIf { it.isNotEmpty() }?.let { annotations -> + PropertyContainer.withAll(annotations.toSourceSetDependent().toAnnotations()) + } ?: PropertyContainer.empty() + + private fun getBound(type: PsiType): Bound { + //We would like to cache most of the bounds since it is not common to annotate them, + //but if this is the case, we treat them as 'one of' + fun PsiType.cacheBoundIfHasNoAnnotation(f: (List) -> Bound): Bound { + val annotations = this.annotations.toList().toListOfAnnotations() + return if (annotations.isNotEmpty()) f(annotations) + else cachedBounds.getOrPut(canonicalText) { + f(annotations) + } + } + + return when (type) { + is PsiClassType -> + type.resolve()?.let { resolved -> + when { + resolved.qualifiedName == "java.lang.Object" -> type.cacheBoundIfHasNoAnnotation { annotations -> JavaObject(annotations.annotations()) } + resolved is PsiTypeParameter -> { + TypeParameter( + dri = DRI.from(resolved), + name = resolved.name.orEmpty(), + extra = type.annotations() + ) + } + + Regex("kotlin\\.jvm\\.functions\\.Function.*").matches(resolved.qualifiedName ?: "") || + Regex("java\\.util\\.function\\.Function.*").matches( + resolved.qualifiedName ?: "" + ) -> FunctionalTypeConstructor( + DRI.from(resolved), + type.parameters.map { getProjection(it) }, + extra = type.annotations() + ) + + else -> { + // cache types that have no annotation and no type parameter + // since we cache only by name and type parameters depend on context + val typeParameters = type.parameters.map { getProjection(it) } + if (typeParameters.isEmpty()) + type.cacheBoundIfHasNoAnnotation { annotations -> + GenericTypeConstructor( + DRI.from(resolved), + typeParameters, + extra = annotations.annotations() + ) + } + else + GenericTypeConstructor( + DRI.from(resolved), + typeParameters, + extra = type.annotations() + ) + } + } + } ?: UnresolvedBound(type.presentableText, type.annotations()) + + is PsiArrayType -> GenericTypeConstructor( + DRI("kotlin", "Array"), + listOf(getProjection(type.componentType)), + extra = type.annotations() + ) + + is PsiPrimitiveType -> if (type.name == "void") Void + else type.cacheBoundIfHasNoAnnotation { annotations -> PrimitiveJavaType(type.name, annotations.annotations()) } + else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser") + } + } + + + private fun getVariance(type: PsiWildcardType): Projection = when { + type.extendsBound != PsiType.NULL -> Covariance(getBound(type.extendsBound)) + type.superBound != PsiType.NULL -> Contravariance(getBound(type.superBound)) + else -> throw IllegalStateException("${type.presentableText} has incorrect bounds") + } + + private fun getProjection(type: PsiType): Projection = when (type) { + is PsiEllipsisType -> Star + is PsiWildcardType -> getVariance(type) + else -> getBound(type) + } + + private fun PsiModifierListOwner.getModifier() = when { + hasModifier(JvmModifier.ABSTRACT) -> JavaModifier.Abstract + hasModifier(JvmModifier.FINAL) -> JavaModifier.Final + else -> JavaModifier.Empty + } + + private fun PsiTypeParameterListOwner.mapTypeParameters(dri: DRI): List { + fun mapBounds(bounds: Array): List = + if (bounds.isEmpty()) emptyList() else bounds.mapNotNull { + (it as? PsiClassType)?.let { classType -> Nullable(getBound(classType)) } + } + return typeParameters.map { type -> + DTypeParameter( + dri = dri.copy(target = dri.target.nextTarget()), + name = type.name.orEmpty(), + presentableName = null, + documentation = javadocParser.parseDocumentation(type).toSourceSetDependent(), + expectPresentInSet = null, + bounds = mapBounds(type.bounds), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( + type.annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations() + ) + ) + } + } + + private fun parseFieldWithInheritingAccessors( + psi: PsiField, + accessors: List>, + inheritedFrom: DRI + ): DProperty { + val getter = accessors + .firstOrNull { (method, _) -> method.isGetterFor(psi) } + ?.let { (method, dri) -> parseFunction(method, inheritedFrom = dri) } + + val setter = accessors + .firstOrNull { (method, _) -> method.isSetterFor(psi) } + ?.let { (method, dri) -> parseFunction(method, inheritedFrom = dri) } + + return parseField( + psi = psi, + getter = getter, + setter = setter, + inheritedFrom = inheritedFrom + ) + } + + private fun parseField(psi: PsiField, accessors: List, inheritedFrom: DRI? = null): DProperty { + val getter = accessors.firstOrNull { it.isGetterFor(psi) }?.let { parseFunction(it) } + val setter = accessors.firstOrNull { it.isSetterFor(psi) }?.let { parseFunction(it) } + return parseField( + psi = psi, + getter = getter, + setter = setter, + inheritedFrom = inheritedFrom + ) + } + + private fun parseField(psi: PsiField, getter: DFunction?, setter: DFunction?, inheritedFrom: DRI? = null): DProperty { + val dri = DRI.from(psi) + + // non-final java field without accessors should be a var + // setter should be not null when inheriting kotlin vars + val isMutable = !psi.hasModifierProperty("final") + val isVar = (isMutable && getter == null && setter == null) || (getter != null && setter != null) + + return DProperty( + dri = dri, + name = psi.name, + documentation = javadocParser.parseDocumentation(psi).toSourceSetDependent(), + expectPresentInSet = null, + sources = psi.parseSources(), + visibility = psi.getVisibility(getter).toSourceSetDependent(), + type = getBound(psi.type), + receiver = null, + setter = setter, + getter = getter, + modifier = psi.getModifier().toSourceSetDependent(), + sourceSets = setOf(sourceSetData), + generics = emptyList(), + isExpectActual = false, + extra = psi.additionalExtras().let { + val psiAnnotations = psi.annotations.toList() + val parsedAnnotations = psiAnnotations.toListOfAnnotations() + val extraModifierAnnotations = it.toListOfAnnotations() + val jvmFieldAnnotation = psiAnnotations.findJvmFieldAnnotation() + val annotations = parsedAnnotations + extraModifierAnnotations + listOfNotNull(jvmFieldAnnotation) + + PropertyContainer.withAll( + inheritedFrom?.let { inheritedFrom -> InheritedMember(inheritedFrom.toSourceSetDependent()) }, + it.toSourceSetDependent().toAdditionalModifiers(), + annotations.toSourceSetDependent().toAnnotations(), + psi.getConstantExpression()?.let { DefaultValue(it.toSourceSetDependent()) }, + takeIf { isVar }?.let { IsVar } + ) + } + ) + } + + private fun PsiField.getVisibility(getter: DFunction?): Visibility { + return getter?.visibility?.get(sourceSetData) ?: this.getVisibility() + } + + private fun Collection.toListOfAnnotations() = + filter { !lightMethodChecker.isLightAnnotation(it) }.mapNotNull { it.toAnnotation() } + + private fun PsiField.getConstantExpression(): Expression? { + val constantValue = this.computeConstantValue() ?: return null + return when (constantValue) { + is Byte -> IntegerConstant(constantValue.toLong()) + is Short -> IntegerConstant(constantValue.toLong()) + is Int -> IntegerConstant(constantValue.toLong()) + is Long -> IntegerConstant(constantValue) + is Char -> StringConstant(constantValue.toString()) + is String -> StringConstant(constantValue) + is Double -> DoubleConstant(constantValue) + is Float -> FloatConstant(constantValue) + is Boolean -> BooleanConstant(constantValue) + else -> ComplexExpression(constantValue.toString()) + } + } + + private fun JvmAnnotationAttribute.toValue(): AnnotationParameterValue = when (this) { + is PsiNameValuePair -> value?.toValue() ?: attributeValue?.toValue() ?: StringValue("") + else -> StringValue(this.attributeName) + }.let { annotationValue -> + if (annotationValue is StringValue) annotationValue.copy(annotationValue.value.removeSurrounding("\"")) + else annotationValue + } + + /** + * This is a workaround for static imports from JDK like RetentionPolicy + * For some reason they are not represented in the same way than using normal import + */ + private fun JvmAnnotationAttributeValue.toValue(): AnnotationParameterValue? { + return when (this) { + is JvmAnnotationEnumFieldValue -> (field as? PsiElement)?.let { EnumValue(fieldName ?: "", DRI.from(it)) } + // static import of a constant is resolved to constant value instead of a field/link + is JvmAnnotationConstantValue -> this.constantValue?.toAnnotationLiteralValue() + else -> null + } + } + + private fun Any.toAnnotationLiteralValue() = when (this) { + is Byte -> IntValue(this.toInt()) + is Short -> IntValue(this.toInt()) + is Char -> StringValue(this.toString()) + is Int -> IntValue(this) + is Long -> LongValue(this) + is Boolean -> BooleanValue(this) + is Float -> FloatValue(this) + is Double -> DoubleValue(this) + else -> StringValue(this.toString()) + } + + private fun PsiAnnotationMemberValue.toValue(): AnnotationParameterValue? = when (this) { + is PsiAnnotation -> toAnnotation()?.let { AnnotationValue(it) } + is PsiArrayInitializerMemberValue -> ArrayValue(initializers.mapNotNull { it.toValue() }) + is PsiReferenceExpression -> psiReference?.let { EnumValue(text ?: "", DRI.from(it)) } + is PsiClassObjectAccessExpression -> { + val parameterType = (type as? PsiClassType)?.parameters?.firstOrNull() + val classType = when (parameterType) { + is PsiClassType -> parameterType.resolve() + // Notice: Array::class will be passed down as String::class + // should probably be Array::class instead but this reflects behaviour for Kotlin sources + is PsiArrayType -> (parameterType.componentType as? PsiClassType)?.resolve() + else -> null + } + classType?.let { ClassValue(it.name ?: "", DRI.from(it)) } + } + is PsiLiteralExpression -> toValue() + else -> StringValue(text ?: "") + } + + private fun PsiLiteralExpression.toValue(): AnnotationParameterValue? = when (type) { + PsiType.INT -> (value as? Int)?.let { IntValue(it) } + PsiType.LONG -> (value as? Long)?.let { LongValue(it) } + PsiType.FLOAT -> (value as? Float)?.let { FloatValue(it) } + PsiType.DOUBLE -> (value as? Double)?.let { DoubleValue(it) } + PsiType.BOOLEAN -> (value as? Boolean)?.let { BooleanValue(it) } + PsiType.NULL -> NullValue + else -> StringValue(text ?: "") + } + + private fun PsiAnnotation.toAnnotation(): Annotations.Annotation? { + // TODO Mitigating workaround for issue https://github.com/Kotlin/dokka/issues/1341 + // Tracking https://youtrack.jetbrains.com/issue/KT-41234 + // Needs to be removed once this issue is fixed in light classes + fun PsiElement.getAnnotationsOrNull(): Array? { + this as PsiClass + return try { + this.annotations + } catch (e: Exception) { + logger.warn("Failed to get annotations from ${this.qualifiedName}") + null + } + } + + return psiReference?.let { psiElement -> + Annotations.Annotation( + dri = DRI.from(psiElement), + params = attributes + .filter { !lightMethodChecker.isLightAnnotationAttribute(it) } + .mapNotNull { it.attributeName to it.toValue() } + .toMap(), + mustBeDocumented = psiElement.getAnnotationsOrNull().orEmpty().any { annotation -> + annotation.hasQualifiedName("java.lang.annotation.Documented") + } + ) + } + } + + private val PsiElement.psiReference + get() = getChildOfType()?.resolve() +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt new file mode 100644 index 00000000000..5db0f29acbb --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt @@ -0,0 +1,99 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiAnnotation +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.analysis.java.doctag.InheritDocTagContentProvider +import org.jetbrains.dokka.analysis.java.parsers.JavaPsiDocCommentParser +import org.jetbrains.dokka.analysis.java.parsers.doctag.InheritDocTagResolver +import org.jetbrains.dokka.analysis.java.parsers.doctag.PsiDocTagParser +import org.jetbrains.dokka.plugability.* +import java.io.File + + +@InternalDokkaApi +interface ProjectProvider { + fun getProject(sourceSet: DokkaSourceSet, context: DokkaContext): Project +} + +@InternalDokkaApi +interface SourceRootsExtractor { + fun extract(sourceSet: DokkaSourceSet, context: DokkaContext): List +} + +@InternalDokkaApi +interface BreakingAbstractionKotlinLightMethodChecker { + fun isLightAnnotation(annotation: PsiAnnotation): Boolean + fun isLightAnnotationAttribute(attribute: JvmAnnotationAttribute): Boolean +} + +@InternalDokkaApi +class JavaAnalysisPlugin : DokkaPlugin() { + + // single + val projectProvider by extensionPoint() + + // single + val sourceRootsExtractor by extensionPoint() + + // multiple + val docCommentCreators by extensionPoint() + + // multiple + val docCommentParsers by extensionPoint() + + // none or more + val inheritDocTagContentProviders by extensionPoint() + + // TODO [beresnev] figure out a better way depending on what it's used for + val kotlinLightMethodChecker by extensionPoint() + + private val docCommentFactory by lazy { + DocCommentFactory(query { docCommentCreators }.reversed()) + } + + val docCommentFinder by lazy { + DocCommentFinder(logger, docCommentFactory) + } + + internal val javaDocCommentCreator by extending { + docCommentCreators providing { JavaDocCommentCreator() } + } + + private val psiDocTagParser by lazy { + PsiDocTagParser( + inheritDocTagResolver = InheritDocTagResolver( + docCommentFactory = docCommentFactory, + docCommentFinder = docCommentFinder, + contentProviders = query { inheritDocTagContentProviders } + ) + ) + } + + internal val javaDocCommentParser by extending { + docCommentParsers providing { + JavaPsiDocCommentParser( + psiDocTagParser + ) + } + } + + internal val psiToDocumentableTranslator by extending { + CoreExtensions.sourceToDocumentableTranslator providing { DefaultPsiToDocumentableTranslator() } + } + + @OptIn(DokkaPluginApiPreview::class) + override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement + + private companion object { + init { + // Suppress messages emitted by the IntelliJ logger since + // there's not much the end user can do about it + Logger.setFactory(NoopIntellijLoggerFactory()) + } + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocComment.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocComment.kt new file mode 100644 index 00000000000..cd901cbb1b3 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocComment.kt @@ -0,0 +1,82 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiElement +import com.intellij.psi.javadoc.PsiDocComment +import com.intellij.psi.javadoc.PsiDocTag +import org.jetbrains.dokka.analysis.java.util.contentElementsWithSiblingIfNeeded +import org.jetbrains.dokka.analysis.java.util.getKotlinFqName +import org.jetbrains.dokka.analysis.java.util.hasTag +import org.jetbrains.dokka.analysis.java.util.resolveToElement + +internal class JavaDocComment(val comment: PsiDocComment) : DocComment { + override fun hasTag(tag: JavadocTag): Boolean { + return when (tag) { + is ThrowingExceptionJavadocTag -> hasTag(tag) + else -> comment.hasTag(tag) + } + } + + private fun hasTag(tag: ThrowingExceptionJavadocTag): Boolean = + comment.hasTag(tag) && comment.resolveTag(tag).filterIsInstance().firstOrNull() + ?.resolveToElement() + ?.getKotlinFqName() == tag.exceptionQualifiedName + + override fun resolveTag(tag: JavadocTag): List { + return when (tag) { + is ParamJavadocTag -> resolveParamTag(tag) + is ThrowingExceptionJavadocTag -> resolveThrowingTag(tag) + else -> comment.resolveTag(tag).map { PsiDocumentationContent(it, tag) } + } + } + + private fun resolveParamTag(tag: ParamJavadocTag): List { + val resolvedParamElements = comment.resolveTag(tag) + .filterIsInstance() + .map { it.contentElementsWithSiblingIfNeeded() } + .firstOrNull { + it.firstOrNull()?.text == tag.method.parameterList.parameters[tag.paramIndex].name + }.orEmpty() + + return resolvedParamElements + .withoutReferenceLink() + .map { PsiDocumentationContent(it, tag) } + } + + private fun resolveThrowingTag(tag: ThrowingExceptionJavadocTag): List { + val resolvedElements = comment.resolveTag(tag) + .flatMap { + when (it) { + is PsiDocTag -> it.contentElementsWithSiblingIfNeeded() + else -> listOf(it) + } + } + + return resolvedElements + .withoutReferenceLink() + .map { PsiDocumentationContent(it, tag) } + } + + private fun PsiDocComment.resolveTag(tag: JavadocTag): List { + return when (tag) { + DescriptionJavadocTag -> this.descriptionElements.toList() + else -> this.findTagsByName(tag.name).toList() + } + } + + private fun List.withoutReferenceLink(): List = drop(1) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as JavaDocComment + + if (comment != other.comment) return false + + return true + } + + override fun hashCode(): Int { + return comment.hashCode() + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocCommentCreator.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocCommentCreator.kt new file mode 100644 index 00000000000..888f1b7f085 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaDocCommentCreator.kt @@ -0,0 +1,11 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiDocCommentOwner +import com.intellij.psi.PsiNamedElement + +internal class JavaDocCommentCreator : DocCommentCreator { + override fun create(element: PsiNamedElement): DocComment? { + val psiDocComment = (element as? PsiDocCommentOwner)?.docComment ?: return null + return JavaDocComment(psiDocComment) + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt new file mode 100644 index 00000000000..f5cd550ff5a --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt @@ -0,0 +1,48 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiMethod +import org.jetbrains.dokka.InternalDokkaApi + +@InternalDokkaApi +sealed class JavadocTag(val name: String) + +object AuthorJavadocTag : JavadocTag("author") +object DeprecatedJavadocTag : JavadocTag("deprecated") +object DescriptionJavadocTag : JavadocTag("description") +object ReturnJavadocTag : JavadocTag("return") +object SinceJavadocTag : JavadocTag("since") + +class ParamJavadocTag( + val method: PsiMethod, + val paramName: String, + val paramIndex: Int +) : JavadocTag(name) { + companion object { + const val name: String = "param" + } +} + +class SeeJavadocTag( + val qualifiedReference: String +) : JavadocTag(name) { + companion object { + const val name: String = "see" + } +} + +sealed class ThrowingExceptionJavadocTag( + name: String, + val exceptionQualifiedName: String? +) : JavadocTag(name) + +class ThrowsJavadocTag(exceptionQualifiedName: String?) : ThrowingExceptionJavadocTag(name, exceptionQualifiedName) { + companion object { + const val name: String = "throws" + } +} + +class ExceptionJavadocTag(exceptionQualifiedName: String?) : ThrowingExceptionJavadocTag(name, exceptionQualifiedName) { + companion object { + const val name: String = "exception" + } +} diff --git a/plugins/base/src/main/kotlin/utils/NoopIntellijLogger.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/NoopIntellijLogger.kt similarity index 97% rename from plugins/base/src/main/kotlin/utils/NoopIntellijLogger.kt rename to analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/NoopIntellijLogger.kt index 9248f9967fa..9ee0a0dfdf7 100644 --- a/plugins/base/src/main/kotlin/utils/NoopIntellijLogger.kt +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/NoopIntellijLogger.kt @@ -1,4 +1,4 @@ -package org.jetbrains.dokka.base.utils +package org.jetbrains.dokka.analysis.java import com.intellij.openapi.diagnostic.Attachment import com.intellij.openapi.diagnostic.DefaultLogger diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/PsiDocumentationContent.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/PsiDocumentationContent.kt new file mode 100644 index 00000000000..458dd95f5ec --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/PsiDocumentationContent.kt @@ -0,0 +1,21 @@ +package org.jetbrains.dokka.analysis.java + +import com.intellij.psi.PsiElement +import com.intellij.psi.javadoc.PsiDocTag +import org.jetbrains.dokka.analysis.java.util.contentElementsWithSiblingIfNeeded + +internal data class PsiDocumentationContent( + val psiElement: PsiElement, + override val tag: JavadocTag +) : DocumentationContent { + + override fun resolveSiblings(): List { + return if (psiElement is PsiDocTag) { + psiElement.contentElementsWithSiblingIfNeeded() + .map { content -> PsiDocumentationContent(content, tag) } + } else { + listOf(this) + } + } + +} diff --git a/plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt similarity index 72% rename from plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt rename to analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt index 376c0940dc8..d780bb40341 100644 --- a/plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt @@ -1,17 +1,20 @@ -package org.jetbrains.dokka.base.translators.psi +package org.jetbrains.dokka.analysis.java -import com.intellij.psi.* +import com.intellij.openapi.project.Project +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.SyntheticElement import com.intellij.psi.javadoc.PsiDocComment -import org.jetbrains.dokka.analysis.DokkaResolutionFacade -import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser +import org.jetbrains.dokka.analysis.java.parsers.JavaPsiDocCommentParser import org.jetbrains.dokka.model.doc.DocumentationNode private const val ENUM_VALUEOF_TEMPLATE_PATH = "/dokka/docs/javadoc/EnumValueOf.java.template" private const val ENUM_VALUES_TEMPLATE_PATH = "/dokka/docs/javadoc/EnumValues.java.template" internal class SyntheticElementDocumentationProvider( - private val javadocParser: JavadocParser, - private val resolutionFacade: DokkaResolutionFacade + private val javadocParser: JavaPsiDocCommentParser, + private val project: Project ) { fun isDocumented(psiElement: PsiElement): Boolean = psiElement is PsiMethod && (psiElement.isSyntheticEnumValuesMethod() || psiElement.isSyntheticEnumValueOfMethod()) @@ -24,12 +27,12 @@ internal class SyntheticElementDocumentationProvider( else -> return null } val docComment = loadSyntheticDoc(templatePath) ?: return null - return javadocParser.parseDocComment(docComment, psiElement) + return javadocParser.parsePsiDocComment(docComment, psiElement) } private fun loadSyntheticDoc(path: String): PsiDocComment? { val text = javaClass.getResource(path)?.readText() ?: return null - return JavaPsiFacade.getElementFactory(resolutionFacade.project).createDocCommentFromText(text) + return JavaPsiFacade.getElementFactory(project).createDocCommentFromText(text) } } diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/DocTagParserContext.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/DocTagParserContext.kt new file mode 100644 index 00000000000..ac0b9ee3f55 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/DocTagParserContext.kt @@ -0,0 +1,47 @@ +package org.jetbrains.dokka.analysis.java.doctag + +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.doc.DocumentationNode +import java.util.* + +@InternalDokkaApi +class DocTagParserContext { + /** + * exists for resolving `@link element` links, where the referenced + * PSI element is mapped as DRI + * + * only used in the context of parsing to html and then from html to doctag + */ + private val driMap = mutableMapOf() + + /** + * Cache created to make storing entries from kotlin easier. + * + * It has to be mutable to allow for adding entries when @inheritDoc resolves to kotlin code, + * from which we get a DocTags not descriptors. + */ + private val inheritDocSections = mutableMapOf() + + /** + * @return key of the stored DRI + */ + fun store(dri: DRI): String { + val id = dri.toString() + driMap[id] = dri + return id + } + + /** + * @return key of the stored documentation node + */ + fun store(documentationNode: DocumentationNode): String { + val id = UUID.randomUUID().toString() + inheritDocSections[id] = documentationNode + return id + } + + fun getDri(id: String): DRI? = driMap[id] + + fun getDocumentationNode(id: String): DocumentationNode? = inheritDocSections[id] +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/InheritDocTagContentProvider.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/InheritDocTagContentProvider.kt new file mode 100644 index 00000000000..a588624fb82 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doctag/InheritDocTagContentProvider.kt @@ -0,0 +1,10 @@ +package org.jetbrains.dokka.analysis.java.doctag + +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.analysis.java.DocumentationContent + +@InternalDokkaApi +interface InheritDocTagContentProvider { + fun canConvert(content: DocumentationContent): Boolean + fun convertToHtml(content: DocumentationContent, docTagParserContext: DocTagParserContext): String +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt new file mode 100644 index 00000000000..1e1936481d7 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt @@ -0,0 +1,9 @@ +package org.jetbrains.dokka.analysis.java.parsers + +import com.intellij.psi.javadoc.PsiDocComment +import org.jetbrains.dokka.analysis.java.JavadocTag + +internal data class CommentResolutionContext( + val comment: PsiDocComment, + val tag: JavadocTag? +) diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt new file mode 100644 index 00000000000..995bdd0d130 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt @@ -0,0 +1,226 @@ +package org.jetbrains.dokka.analysis.java.parsers + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.impl.source.tree.JavaDocElementType +import com.intellij.psi.impl.source.tree.LazyParseablePsiElement +import com.intellij.psi.javadoc.PsiDocComment +import com.intellij.psi.javadoc.PsiDocTag + +import org.jetbrains.dokka.analysis.java.* +import org.jetbrains.dokka.analysis.java.parsers.doctag.PsiDocTagParser +import org.jetbrains.dokka.analysis.java.util.* +import org.jetbrains.dokka.analysis.markdown.MARKDOWN_FILE_NAME +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.model.doc.Deprecated + +internal class JavaPsiDocCommentParser( + private val psiDocTagParser: PsiDocTagParser, +) : DocCommentParser { + + override fun canParse(docComment: DocComment): Boolean { + return docComment is JavaDocComment + } + + override fun parse(docComment: DocComment, context: PsiNamedElement): DocumentationNode { + val javaDocComment = docComment as JavaDocComment + return parsePsiDocComment(javaDocComment.comment, context) + } + + internal fun parsePsiDocComment(docComment: PsiDocComment, context: PsiNamedElement): DocumentationNode { + val description = listOfNotNull(docComment.getDescription()) + val tags = docComment.tags.mapNotNull { tag -> + parseDocTag(tag, docComment, context) + } + return DocumentationNode(description + tags) + } + + private fun PsiDocComment.getDescription(): Description? { + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = descriptionElements.asIterable(), + commentResolutionContext = CommentResolutionContext(this, DescriptionJavadocTag), + ) + return docTags.takeIf { it.isNotEmpty() }?.let { + Description(wrapTagIfNecessary(it)) + } + } + + private fun parseDocTag(tag: PsiDocTag, docComment: PsiDocComment, analysedElement: PsiNamedElement): TagWrapper? { + return when (tag.name) { + ParamJavadocTag.name -> parseParamTag(tag, docComment, analysedElement) + ThrowsJavadocTag.name, ExceptionJavadocTag.name -> parseThrowsTag(tag, docComment) + ReturnJavadocTag.name -> parseReturnTag(tag, docComment) + SinceJavadocTag.name -> parseSinceTag(tag, docComment) + AuthorJavadocTag.name -> parseAuthorTag(tag, docComment) + SeeJavadocTag.name -> parseSeeTag(tag, docComment) + DeprecatedJavadocTag.name -> parseDeprecatedTag(tag, docComment) + else -> emptyTagWrapper(tag, docComment) + } + } + + private fun parseParamTag( + tag: PsiDocTag, + docComment: PsiDocComment, + analysedElement: PsiNamedElement + ): TagWrapper? { + val paramName = tag.dataElements.firstOrNull()?.text.orEmpty() + + // can be a PsiClass if @param is referencing class generics, like here: + // https://github.com/biojava/biojava/blob/2417c230be36e4ba73c62bb3631b60f876265623/biojava-core/src/main/java/org/biojava/nbio/core/alignment/SimpleProfilePair.java#L43 + // not supported at the moment + val method = analysedElement as? PsiMethod ?: return null + val paramIndex = method.parameterList.parameters.map { it.name }.indexOf(paramName) + + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.contentElementsWithSiblingIfNeeded().drop(1), + commentResolutionContext = CommentResolutionContext( + comment = docComment, + tag = ParamJavadocTag(method, paramName, paramIndex) + ) + ) + return Param(root = wrapTagIfNecessary(docTags), name = paramName) + } + + private fun parseThrowsTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): Throws { + val resolvedElement = tag.resolveToElement() + val exceptionAddress = resolvedElement?.let { DRI.from(it) } + + /* we always would like to have a fully qualified name as name, + * because it will be used as a display name later and we would like to have those unified + * even if documentation states shortened version + * Only if dri search fails we should use the provided phrase (since then we are not able to get a fq name) + */ + val fullyQualifiedExceptionName = + resolvedElement?.getKotlinFqName() ?: tag.dataElements.firstOrNull()?.text.orEmpty() + + val javadocTag = when (tag.name) { + ThrowsJavadocTag.name -> ThrowsJavadocTag(fullyQualifiedExceptionName) + ExceptionJavadocTag.name -> ExceptionJavadocTag(fullyQualifiedExceptionName) + else -> throw IllegalArgumentException("Expected @throws or @exception") + } + + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.dataElements.drop(1), + commentResolutionContext = CommentResolutionContext( + comment = docComment, + tag = javadocTag + ), + ) + return Throws( + root = wrapTagIfNecessary(docTags), + name = fullyQualifiedExceptionName, + exceptionAddress = exceptionAddress + ) + } + + private fun parseReturnTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): Return { + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.contentElementsWithSiblingIfNeeded(), + commentResolutionContext = CommentResolutionContext(comment = docComment, tag = ReturnJavadocTag), + ) + return Return(root = wrapTagIfNecessary(docTags)) + } + + private fun parseSinceTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): Since { + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.contentElementsWithSiblingIfNeeded(), + commentResolutionContext = CommentResolutionContext(comment = docComment, tag = ReturnJavadocTag), + ) + return Since(root = wrapTagIfNecessary(docTags)) + } + + private fun parseAuthorTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): Author { + // TODO [beresnev] see what the hell this is + // Workaround: PSI returns first word after @author tag as a `DOC_TAG_VALUE_ELEMENT`, + // then the rest as a `DOC_COMMENT_DATA`, so for `Name Surname` we get them parted + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.contentElementsWithSiblingIfNeeded(), + commentResolutionContext = CommentResolutionContext(comment = docComment, tag = AuthorJavadocTag), + ) + return Author(root = wrapTagIfNecessary(docTags)) + } + + private fun parseSeeTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): See { + val referenceElement = tag.referenceElement() + val fullyQualifiedSeeReference = tag.resolveToElement()?.getKotlinFqName() + ?: referenceElement?.text.orEmpty().removePrefix("#") + + val context = CommentResolutionContext(comment = docComment, tag = SeeJavadocTag(fullyQualifiedSeeReference)) + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.dataElements.dropWhile { + it is PsiWhiteSpace || it.isDocReferenceHolder() || it == referenceElement + }, + commentResolutionContext = context, + ) + + return See( + root = wrapTagIfNecessary(docTags), + name = fullyQualifiedSeeReference, + address = referenceElement?.toDocumentationLink(context = context)?.dri + ) + } + + private fun PsiElement.isDocReferenceHolder(): Boolean { + return (this as? LazyParseablePsiElement)?.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER + } + + private fun parseDeprecatedTag( + tag: PsiDocTag, + docComment: PsiDocComment + ): Deprecated { + val docTags = psiDocTagParser.parseAsParagraph( + tag.contentElementsWithSiblingIfNeeded(), + CommentResolutionContext(comment = docComment, tag = DeprecatedJavadocTag), + ) + return Deprecated(root = wrapTagIfNecessary(docTags)) + } + + private fun wrapTagIfNecessary(tags: List): CustomDocTag { + val isFile = (tags.singleOrNull() as? CustomDocTag)?.name == MARKDOWN_FILE_NAME + return if (isFile) { + tags.first() as CustomDocTag + } else { + CustomDocTag(tags, name = MARKDOWN_FILE_NAME) + } + } + + // Wrapper for unsupported tags https://github.com/Kotlin/dokka/issues/1618 + private fun emptyTagWrapper( + tag: PsiDocTag, + docComment: PsiDocComment, + ): CustomTagWrapper { + val docTags = psiDocTagParser.parseAsParagraph( + psiElements = tag.contentElementsWithSiblingIfNeeded(), + commentResolutionContext = CommentResolutionContext(docComment, null), + ) + return CustomTagWrapper( + root = wrapTagIfNecessary(docTags), + name = tag.name + ) + } + + private fun PsiElement.toDocumentationLink(labelElement: PsiElement? = null, context: CommentResolutionContext): DocumentationLink? { + val resolvedElement = this.resolveToGetDri() ?: return null + val label = labelElement ?: defaultLabel() + val docTags = psiDocTagParser.parse(listOfNotNull(label), context) + return DocumentationLink(dri = DRI.from(resolvedElement), children = docTags) + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt new file mode 100644 index 00000000000..b80426e6d61 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt @@ -0,0 +1,25 @@ +package org.jetbrains.dokka.analysis.java.parsers + +import com.intellij.psi.PsiNamedElement +import org.jetbrains.dokka.InternalDokkaApi +import org.jetbrains.dokka.analysis.java.DocCommentFinder +import org.jetbrains.dokka.analysis.java.DocCommentParser +import org.jetbrains.dokka.model.doc.DocumentationNode + +internal fun interface JavaDocumentationParser { + fun parseDocumentation(element: PsiNamedElement): DocumentationNode +} + +@InternalDokkaApi +class JavadocParser( + private val docCommentParsers: List, + private val docCommentFinder: DocCommentFinder +) : JavaDocumentationParser { + + override fun parseDocumentation(element: PsiNamedElement): DocumentationNode { + val comment = docCommentFinder.findClosestToElement(element) ?: return DocumentationNode(emptyList()) + return docCommentParsers + .first { it.canParse(comment) } + .parse(comment, element) + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt new file mode 100644 index 00000000000..96362d956b8 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt @@ -0,0 +1,115 @@ +package org.jetbrains.dokka.analysis.java.parsers.doctag + +import org.jetbrains.dokka.analysis.java.doctag.DocTagParserContext +import org.jetbrains.dokka.analysis.markdown.parseHtmlEncodedWithNormalisedSpaces +import org.jetbrains.dokka.model.doc.* +import org.jsoup.Jsoup +import org.jsoup.nodes.Comment +import org.jsoup.nodes.Element +import org.jsoup.nodes.Node +import org.jsoup.nodes.TextNode + +internal class HtmlToDocTagConverter( + private val docTagParserContext: DocTagParserContext +) { + fun convertToDocTag(html: String): List { + return Jsoup.parseBodyFragment(html) + .body() + .childNodes() + .flatMap { convertHtmlNode(it) } + } + + private fun convertHtmlNode(node: Node, keepFormatting: Boolean = false): List = when (node) { + is TextNode -> (if (keepFormatting) { + node.wholeText.takeIf { it.isNotBlank() }?.let { listOf(Text(body = it)) } + } else { + node.wholeText.parseHtmlEncodedWithNormalisedSpaces(renderWhiteCharactersAsSpaces = true) + }).orEmpty() + is Comment -> listOf(Text(body = node.outerHtml(), params = DocTag.contentTypeParam("html"))) + is Element -> createBlock(node, keepFormatting) + else -> emptyList() + } + + private fun createBlock(element: Element, keepFormatting: Boolean = false): List { + val tagName = element.tagName() + val children = element.childNodes() + .flatMap { convertHtmlNode(it, keepFormatting = keepFormatting || tagName == "pre" || tagName == "code") } + + fun ifChildrenPresent(operation: () -> DocTag): List { + return if (children.isNotEmpty()) listOf(operation()) else emptyList() + } + return when (tagName) { + "blockquote" -> ifChildrenPresent { BlockQuote(children) } + "p" -> ifChildrenPresent { P(children) } + "b" -> ifChildrenPresent { B(children) } + "strong" -> ifChildrenPresent { Strong(children) } + "index" -> listOf(Index(children)) + "i" -> ifChildrenPresent { I(children) } + "img" -> listOf( + Img( + children, + element.attributes().associate { (if (it.key == "src") "href" else it.key) to it.value }) + ) + "em" -> listOf(Em(children)) + "code" -> ifChildrenPresent { if(keepFormatting) CodeBlock(children) else CodeInline(children) } + "pre" -> if(children.size == 1) { + when(children.first()) { + is CodeInline -> listOf(CodeBlock(children.first().children)) + is CodeBlock -> listOf(children.first()) + else -> listOf(Pre(children)) + } + } else { + listOf(Pre(children)) + } + "ul" -> ifChildrenPresent { Ul(children) } + "ol" -> ifChildrenPresent { Ol(children) } + "li" -> listOf(Li(children)) + "dl" -> ifChildrenPresent { Dl(children) } + "dt" -> listOf(Dt(children)) + "dd" -> listOf(Dd(children)) + "a" -> listOf(createLink(element, children)) + "table" -> ifChildrenPresent { Table(children) } + "tr" -> ifChildrenPresent { Tr(children) } + "td" -> listOf(Td(children)) + "thead" -> listOf(THead(children)) + "tbody" -> listOf(TBody(children)) + "tfoot" -> listOf(TFoot(children)) + "caption" -> ifChildrenPresent { Caption(children) } + "inheritdoc" -> { + // TODO [beresnev] describe how it works + val id = element.attr("id") + val section = docTagParserContext.getDocumentationNode(id) + val parsed = section?.children?.flatMap { it.root.children }.orEmpty() + if(parsed.size == 1 && parsed.first() is P){ + parsed.first().children + } else { + parsed + } + } + "h1" -> ifChildrenPresent { H1(children) } + "h2" -> ifChildrenPresent { H2(children) } + "h3" -> ifChildrenPresent { H3(children) } + "var" -> ifChildrenPresent { Var(children) } + "u" -> ifChildrenPresent { U(children) } + else -> listOf(Text(body = element.ownText())) + } + } + + private fun createLink(element: Element, children: List): DocTag { + return when { + element.hasAttr("docref") -> + A(children, params = mapOf("docref" to element.attr("docref"))) + element.hasAttr("href") -> + A(children, params = mapOf("href" to element.attr("href"))) + element.hasAttr("data-dri") && docTagParserContext.getDri(element.attr("data-dri")) != null -> { + val referencedDriId = element.attr("data-dri") + DocumentationLink( + dri = docTagParserContext.getDri(referencedDriId) + ?: error("docTagParserContext.getDri is null, TODO"), // TODO [beresnev] handle + children = children + ) + } + else -> Text(body = children.filterIsInstance().joinToString { it.body }) + } + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt new file mode 100644 index 00000000000..bf70687b0a6 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt @@ -0,0 +1,114 @@ +package org.jetbrains.dokka.analysis.java.parsers.doctag + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod +import com.intellij.psi.javadoc.PsiDocComment +import org.jetbrains.dokka.analysis.java.* +import org.jetbrains.dokka.analysis.java.doctag.DocTagParserContext +import org.jetbrains.dokka.analysis.java.doctag.InheritDocTagContentProvider +import org.jetbrains.dokka.analysis.java.parsers.CommentResolutionContext + +internal class InheritDocTagResolver( + private val docCommentFactory: DocCommentFactory, + private val docCommentFinder: DocCommentFinder, + private val contentProviders: List +) { + internal fun convertToHtml(content: DocumentationContent, docTagParserContext: DocTagParserContext): String? { + return contentProviders + .firstOrNull { it.canConvert(content) } + ?.convertToHtml(content, docTagParserContext) + } + + internal fun resolveContent(context: CommentResolutionContext): List? { + val javadocTag = context.tag ?: return null + + return when (javadocTag) { + is ThrowingExceptionJavadocTag -> { + javadocTag.exceptionQualifiedName?.let { _ -> + resolveThrowsTag( + javadocTag, + context.comment, + ) + } ?: return null + } + is ParamJavadocTag -> resolveParamTag(context.comment, javadocTag) + is DeprecatedJavadocTag -> resolveGenericTag(context.comment, DescriptionJavadocTag) + is SeeJavadocTag -> emptyList() + else -> resolveGenericTag(context.comment, javadocTag) + } + } + + private fun resolveGenericTag(currentElement: PsiDocComment, tag: JavadocTag): List { + val docComment = when (val owner = currentElement.owner) { + is PsiClass -> lowestClassWithTag(owner, tag) + is PsiMethod -> lowestMethodWithTag(owner, tag) + else -> null + } + return docComment?.resolveTag(tag)?.flatMap { + it.resolveSiblings() + }.orEmpty() + } + + /** + * Main resolution point for exception like tags + * + * This should be used only with [ThrowsJavadocTag] or [ExceptionJavadocTag] as their resolution path should be the same + */ + private fun resolveThrowsTag( + tag: ThrowingExceptionJavadocTag, + currentElement: PsiDocComment, + ): List { + val closestDocsWithThrows = + (currentElement.owner as? PsiMethod)?.let { method -> lowestMethodsWithTag(method, tag) } + .orEmpty().firstOrNull { + docCommentFinder.findClosestToElement(it)?.hasTag(tag) == true + } ?: return emptyList() + + return docCommentFactory.fromElement(closestDocsWithThrows) + ?.resolveTag(tag) + ?: emptyList() + } + + private fun resolveParamTag( + currentElement: PsiDocComment, + paramTag: ParamJavadocTag, + ): List { + val parameterIndex = paramTag.paramIndex + + val methods = (currentElement.owner as? PsiMethod) + ?.let { method -> lowestMethodsWithTag(method, paramTag) } + .orEmpty() + + return methods.flatMap { + if (parameterIndex >= it.parameterList.parametersCount || parameterIndex < 0) { + return@flatMap emptyList() + } + + val closestTag = docCommentFinder.findClosestToElement(it) + val hasTag = closestTag?.hasTag(paramTag) ?: false + closestTag?.takeIf { hasTag }?.resolveTag(ParamJavadocTag(it, "", parameterIndex)) ?: emptyList() + } + } + + //if we are in psi class javadoc only inherits docs from classes and not from interfaces + private fun lowestClassWithTag(baseClass: PsiClass, javadocTag: JavadocTag): DocComment? = + baseClass.superClass?.let { + docCommentFinder.findClosestToElement(it)?.takeIf { tag -> tag.hasTag(javadocTag) } ?: lowestClassWithTag( + it, + javadocTag + ) + } + + private fun lowestMethodWithTag( + baseMethod: PsiMethod, + javadocTag: JavadocTag, + ): DocComment? { + val methodsWithTag = lowestMethodsWithTag(baseMethod, javadocTag).firstOrNull() + return methodsWithTag?.let { + it.docComment?.let { JavaDocComment(it) } ?: docCommentFinder.findClosestToElement(it) + } + } + + private fun lowestMethodsWithTag(baseMethod: PsiMethod, javadocTag: JavadocTag): List = + baseMethod.findSuperMethods().filter { docCommentFinder.findClosestToElement(it)?.hasTag(javadocTag) == true } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt new file mode 100644 index 00000000000..5e7da7ed959 --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt @@ -0,0 +1,41 @@ +package org.jetbrains.dokka.analysis.java.parsers.doctag + +import com.intellij.psi.PsiElement +import com.intellij.psi.javadoc.PsiDocTag +import org.jetbrains.dokka.analysis.java.doctag.DocTagParserContext +import org.jetbrains.dokka.analysis.java.parsers.CommentResolutionContext +import org.jetbrains.dokka.model.doc.* +import java.util.* + +/** + * Parses [PsiElement] of [PsiDocTag] into Dokka's [DocTag] + */ +internal class PsiDocTagParser( + private val inheritDocTagResolver: InheritDocTagResolver +) { + fun parse( + psiElements: Iterable, + commentResolutionContext: CommentResolutionContext + ): List = parse(asParagraph = false, psiElements, commentResolutionContext) + + fun parseAsParagraph( + psiElements: Iterable, + commentResolutionContext: CommentResolutionContext + ): List = parse(asParagraph = true, psiElements, commentResolutionContext) + + private fun parse( + asParagraph: Boolean, + psiElements: Iterable, + commentResolutionContext: CommentResolutionContext + ): List { + val docTagParserContext = DocTagParserContext() + + val psiToHtmlConverter = PsiElementToHtmlConverter(inheritDocTagResolver) + val elementsHtml = psiToHtmlConverter.convert(psiElements, docTagParserContext, commentResolutionContext) + ?: return emptyList() + + val htmlToDocTagConverter = HtmlToDocTagConverter(docTagParserContext) + val html = if (asParagraph) "

$elementsHtml

" else elementsHtml + return htmlToDocTagConverter.convertToDocTag(html) + } +} diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt new file mode 100644 index 00000000000..75ed93c31df --- /dev/null +++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt @@ -0,0 +1,215 @@ +package org.jetbrains.dokka.analysis.java.parsers.doctag + +import com.intellij.lexer.JavaDocTokenTypes +import com.intellij.psi.* +import com.intellij.psi.impl.source.javadoc.PsiDocParamRef +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.javadoc.PsiDocTagValue +import com.intellij.psi.javadoc.PsiDocToken +import com.intellij.psi.javadoc.PsiInlineDocTag +import org.jetbrains.dokka.analysis.java.DocumentationContent +import org.jetbrains.dokka.analysis.java.JavadocTag +import org.jetbrains.dokka.analysis.java.PsiDocumentationContent +import org.jetbrains.dokka.analysis.java.doctag.DocTagParserContext +import org.jetbrains.dokka.analysis.java.parsers.CommentResolutionContext +import org.jetbrains.dokka.analysis.java.util.* +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.utilities.htmlEscape + +private const val UNRESOLVED_PSI_ELEMENT = "UNRESOLVED_PSI_ELEMENT" + +private data class HtmlParserState( + val currentJavadocTag: JavadocTag?, + val previousElement: PsiElement? = null, + val openPreTags: Int = 0, + val closedPreTags: Int = 0 +) + +private data class HtmlParsingResult(val newState: HtmlParserState, val parsedLine: String? = null) { + constructor(tag: JavadocTag?) : this(HtmlParserState(tag)) + + operator fun plus(other: HtmlParsingResult): HtmlParsingResult { + return HtmlParsingResult( + newState = other.newState, + parsedLine = listOfNotNull(parsedLine, other.parsedLine).joinToString(separator = "") + ) + } +} + +internal class PsiElementToHtmlConverter( + private val inheritDocTagResolver: InheritDocTagResolver +) { + private val preOpeningTagRegex = "".toRegex() + private val preClosingTagRegex = "".toRegex() + + fun convert( + psiElements: Iterable, + docTagParserContext: DocTagParserContext, + commentResolutionContext: CommentResolutionContext + ): String? { + return WithContext(docTagParserContext, commentResolutionContext) + .convert(psiElements) + } + + private inner class WithContext( + private val docTagParserContext: DocTagParserContext, + private val commentResolutionContext: CommentResolutionContext + ) { + fun convert(psiElements: Iterable): String? { + val parsingResult = + psiElements.fold(HtmlParsingResult(commentResolutionContext.tag)) { resultAccumulator, psiElement -> + resultAccumulator + parseHtml(psiElement, resultAccumulator.newState) + } + return parsingResult.parsedLine?.trim() + } + + private fun parseHtml(psiElement: PsiElement, state: HtmlParserState): HtmlParsingResult = + when (psiElement) { + is PsiReference -> psiElement.children.fold(HtmlParsingResult(state)) { acc, e -> + acc + parseHtml(e, acc.newState) + } + else -> parseHtmlOfSimpleElement(psiElement, state) + } + + private fun parseHtmlOfSimpleElement(psiElement: PsiElement, state: HtmlParserState): HtmlParsingResult { + val text = psiElement.text + + val openPre = state.openPreTags + preOpeningTagRegex.findAll(text).count() + val closedPre = state.closedPreTags + preClosingTagRegex.findAll(text).count() + val isInsidePre = openPre > closedPre + + val parsed = when (psiElement) { + is PsiInlineDocTag -> psiElement.toHtml(state.currentJavadocTag) + is PsiDocParamRef -> psiElement.toDocumentationLinkString() + is PsiDocTagValue, is LeafPsiElement -> { + psiElement.stringifyElementAsText(isInsidePre, state.previousElement) + } + else -> null + } + val previousElement = if (text.trim() == "") state.previousElement else psiElement + return HtmlParsingResult( + state.copy( + previousElement = previousElement, + closedPreTags = closedPre, + openPreTags = openPre + ), parsed + ) + } + + /** + * Inline tags can be met in the middle of some text. Example of an inline tag usage: + * + * ```java + * Use the {@link #getComponentAt(int, int) getComponentAt} method. + * ``` + */ + private fun PsiInlineDocTag.toHtml(javadocTag: JavadocTag?): String? = + when (this.name) { + "link", "linkplain" -> this.referenceElement() + ?.toDocumentationLinkString(this.dataElements.filterIsInstance().joinToString(" ") { + it.stringifyElementAsText(keepFormatting = false).orEmpty() + }) + + "code" -> "${dataElementsAsText(this)}" + "literal" -> "${dataElementsAsText(this)}" + "index" -> "${this.children.filterIsInstance().joinToString { it.text }}" + "inheritDoc" -> { + val inheritDocContent = inheritDocTagResolver.resolveContent(commentResolutionContext) + val html = inheritDocContent?.fold(HtmlParsingResult(javadocTag)) { result, content -> + result + content.toInheritDocHtml(result.newState, docTagParserContext) + }?.parsedLine.orEmpty() + html + } + + else -> this.text + } + + private fun DocumentationContent.toInheritDocHtml( + parserState: HtmlParserState, + docTagParserContext: DocTagParserContext + ): HtmlParsingResult { + // TODO [beresnev] comment + return if (this is PsiDocumentationContent) { + parseHtml(this.psiElement, parserState) + } else { + HtmlParsingResult(parserState, inheritDocTagResolver.convertToHtml(this, docTagParserContext)) + } + } + + private fun dataElementsAsText(tag: PsiInlineDocTag): String { + return tag.dataElements.joinToString("") { + it.stringifyElementAsText(keepFormatting = true).orEmpty() + }.htmlEscape() + } + + private fun PsiElement.toDocumentationLinkString(label: String = ""): String { + val driId = reference?.resolve()?.takeIf { it !is PsiParameter }?.let { + val dri = DRI.from(it) + val id = docTagParserContext.store(dri) + id + } ?: UNRESOLVED_PSI_ELEMENT // TODO [beresnev] log this somewhere maybe? + + // TODO [beresnev] data-dri into a constant + return """${label.ifBlank { defaultLabel().text }}""" + } + } +} + +private fun PsiElement.stringifyElementAsText(keepFormatting: Boolean, previousElement: PsiElement? = null) = + if (keepFormatting) { + /* + For values in the
 tag we try to keep formatting, so only the leading space is trimmed,
+        since it is there because it separates this line from the leading asterisk
+         */
+        text.let {
+            if (((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true || (prevSibling as? PsiDocToken)?.isTagName() == true) && it.firstOrNull() == ' ')
+                it.drop(1) else it
+        }.let {
+            if ((nextSibling as? PsiDocToken)?.isLeadingAsterisk() == true) it.dropLastWhile { it == ' ' } else it
+        }
+    } else {
+        /*
+        Outside of the 
 we would like to trim everything from the start and end of a line since
+        javadoc doesn't care about it.
+         */
+        text.let {
+            if ((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true && text.isNotBlank() && previousElement !is PsiInlineDocTag) it?.trimStart() else it
+        }?.let {
+            if ((nextSibling as? PsiDocToken)?.isLeadingAsterisk() == true && text.isNotBlank()) it.trimEnd() else it
+        }?.let {
+            if (shouldHaveSpaceAtTheEnd()) "$it " else it
+        }
+    }
+
+private fun PsiDocToken.isLeadingAsterisk() = tokenType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS
+
+private fun PsiDocToken.isTagName() = tokenType == JavaDocTokenType.DOC_TAG_NAME
+
+/**
+ * We would like to know if we need to have a space after a this tag
+ *
+ * The space is required when:
+ *  - tag spans multiple lines, between every line we would need a space
+ *
+ *  We wouldn't like to render a space if:
+ *  - tag is followed by an end of comment
+ *  - after a tag there is another tag (eg. multiple @author tags)
+ *  - they end with an html tag like: Something since then the space will be displayed in the following text
+ *  - next line starts with a 

or

 token
+ */
+private fun PsiElement.shouldHaveSpaceAtTheEnd(): Boolean {
+    val siblings = siblings(withItself = false).toList().filterNot { it.text.trim() == "" }
+    val nextNotEmptySibling = (siblings.firstOrNull() as? PsiDocToken)
+    val furtherNotEmptySibling =
+        (siblings.drop(1).firstOrNull { it is PsiDocToken && !it.isLeadingAsterisk() } as? PsiDocToken)
+    val lastHtmlTag = text.trim().substringAfterLast("<")
+    val endsWithAnUnclosedTag = lastHtmlTag.endsWith(">") && !lastHtmlTag.startsWith(" {
+    fun traverseSupertypes(ancestry: AncestryNode): List =
+        listOf(ancestry.typeConstructor) + (ancestry.superclass?.let(::traverseSupertypes) ?: emptyList())
+
+    return superclass?.let(::traverseSupertypes)?.filter { type -> type.dri.isDirectlyAnException() } ?: emptyList()
+}
+
+// TODO [beresnev] copy-pasted
+internal fun DRI.isDirectlyAnException(): Boolean =
+    toString().let { stringed ->
+        stringed == "kotlin/Exception///PointingToDeclaration/" ||
+                stringed == "java.lang/Exception///PointingToDeclaration/"
+    }
diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt
new file mode 100644
index 00000000000..137f07922d1
--- /dev/null
+++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt
@@ -0,0 +1,101 @@
+package org.jetbrains.dokka.analysis.java.util
+
+// TODO [beresnev] copy-paste
+
+internal fun propertyNamesBySetMethodName(methodName: String): List =
+    listOfNotNull(propertyNameBySetMethodName(methodName, false), propertyNameBySetMethodName(methodName, true))
+
+internal fun propertyNameByGetMethodName(methodName: String): String? =
+    propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is", removePrefix = false)
+
+private fun propertyNameBySetMethodName(methodName: String, withIsPrefix: Boolean): String? =
+    propertyNameFromAccessorMethodName(methodName, "set", addPrefix = if (withIsPrefix) "is" else null)
+
+private fun propertyNameFromAccessorMethodName(
+    methodName: String,
+    prefix: String,
+    removePrefix: Boolean = true,
+    addPrefix: String? = null
+): String? {
+    val isSpecial = methodName.startsWith("<") // see special in org.jetbrains.kotlin.Name
+    if (isSpecial) return null
+    if (!methodName.startsWith(prefix)) return null
+    if (methodName.length == prefix.length) return null
+    if (methodName[prefix.length] in 'a'..'z') return null
+
+    if (addPrefix != null) {
+        assert(removePrefix)
+        return addPrefix + methodName.removePrefix(prefix)
+    }
+
+    if (!removePrefix) return methodName
+    val name = methodName.removePrefix(prefix).decapitalizeSmartForCompiler(asciiOnly = true)
+    if (!isValidIdentifier(name)) return null
+    return name
+}
+
+/**
+ * "FooBar" -> "fooBar"
+ * "FOOBar" -> "fooBar"
+ * "FOO" -> "foo"
+ * "FOO_BAR" -> "foO_BAR"
+ */
+private fun String.decapitalizeSmartForCompiler(asciiOnly: Boolean = false): String {
+    if (isEmpty() || !isUpperCaseCharAt(0, asciiOnly)) return this
+
+    if (length == 1 || !isUpperCaseCharAt(1, asciiOnly)) {
+        return if (asciiOnly) decapitalizeAsciiOnly() else replaceFirstChar(Char::lowercaseChar)
+    }
+
+    val secondWordStart = (indices.firstOrNull { !isUpperCaseCharAt(it, asciiOnly) } ?: return toLowerCase(this, asciiOnly)) - 1
+
+    return toLowerCase(substring(0, secondWordStart), asciiOnly) + substring(secondWordStart)
+}
+
+private fun String.isUpperCaseCharAt(index: Int, asciiOnly: Boolean): Boolean {
+    val c = this[index]
+    return if (asciiOnly) c in 'A'..'Z' else c.isUpperCase()
+}
+
+private fun toLowerCase(string: String, asciiOnly: Boolean): String {
+    return if (asciiOnly) string.toLowerCaseAsciiOnly() else string.lowercase()
+}
+
+private fun toUpperCase(string: String, asciiOnly: Boolean): String {
+    return if (asciiOnly) string.toUpperCaseAsciiOnly() else string.uppercase()
+}
+
+private fun String.decapitalizeAsciiOnly(): String {
+    if (isEmpty()) return this
+    val c = this[0]
+    return if (c in 'A'..'Z')
+        c.lowercaseChar() + substring(1)
+    else
+        this
+}
+
+private fun String.toLowerCaseAsciiOnly(): String {
+    val builder = StringBuilder(length)
+    for (c in this) {
+        builder.append(if (c in 'A'..'Z') c.lowercaseChar() else c)
+    }
+    return builder.toString()
+}
+
+private fun String.toUpperCaseAsciiOnly(): String {
+    val builder = StringBuilder(length)
+    for (c in this) {
+        builder.append(if (c in 'a'..'z') c.uppercaseChar() else c)
+    }
+    return builder.toString()
+}
+
+private fun isValidIdentifier(name: String): Boolean {
+    if (name.isEmpty() || name.startsWith("<")) return false
+    for (element in name) {
+        if (element == '.' || element == '/' || element == '\\') {
+            return false
+        }
+    }
+    return true
+}
diff --git a/plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt
similarity index 75%
rename from plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt
rename to analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt
index 3c1cb2cfc59..1424244d029 100644
--- a/plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt
+++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt
@@ -1,16 +1,11 @@
-package org.jetbrains.dokka.base.translators.psi
+package org.jetbrains.dokka.analysis.java.util
 
 import com.intellij.psi.PsiField
 import com.intellij.psi.PsiMethod
-import org.jetbrains.dokka.base.translators.firstNotNullOfOrNull
+import org.jetbrains.dokka.analysis.java.getVisibility
 import org.jetbrains.dokka.model.JavaVisibility
 import org.jetbrains.dokka.model.KotlinVisibility
 import org.jetbrains.dokka.model.Visibility
-import org.jetbrains.kotlin.load.java.JvmAbi
-import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
-import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.resolve.DescriptorUtils
 
 
 internal data class PsiFunctionsHolder(
@@ -38,6 +33,29 @@ internal fun splitFunctionsAndAccessors(fields: Array, methods: Array<
     return PsiFunctionsHolder(regularFunctions, accessors)
 }
 
+private fun PsiMethod.getPossiblePropertyNamesForFunction(): List {
+    val jvmName = getAnnotation("kotlin.jvm.JvmName")?.findAttributeValue("name")?.text
+    if (jvmName != null) return listOf(jvmName)
+
+    return when {
+            isGetterName(name) -> listOfNotNull(
+                propertyNameByGetMethodName(name)
+            )
+            isSetterName(name) -> {
+                propertyNamesBySetMethodName(name)
+            }
+            else -> listOf()
+        }
+}
+
+private fun isGetterName(name: String): Boolean {
+    return name.startsWith("get") || name.startsWith("is")
+}
+
+private fun isSetterName(name: String): Boolean {
+    return name.startsWith("set")
+}
+
 /**
  * If a field has no getter, it's not accessible as a property from Kotlin's perspective,
  * but it still might have a setter. In this case, this "setter" should be just a regular function
@@ -57,20 +75,6 @@ private fun removeNonAccessorsReturning(
     return nonAccessors
 }
 
-internal fun PsiMethod.getPossiblePropertyNamesForFunction(): List {
-    val jvmName = getAnnotation(DescriptorUtils.JVM_NAME.asString())?.findAttributeValue("name")?.text
-    return jvmName?.let { listOf(jvmName) }
-        ?: when {
-            JvmAbi.isGetterName(name) -> listOfNotNull(
-                propertyNameByGetMethodName(Name.identifier(name))?.asString()
-            )
-            JvmAbi.isSetterName(name) -> {
-                propertyNamesBySetMethodName(Name.identifier(name)).map { it.asString() }
-            }
-            else -> listOf()
-        }
-}
-
 internal fun PsiMethod.isAccessorFor(field: PsiField): Boolean {
     return (this.isGetterFor(field) || this.isSetterFor(field))
             && !field.getVisibility().isPublicAPI()
@@ -85,7 +89,7 @@ internal fun PsiMethod.isSetterFor(field: PsiField): Boolean {
     return parameterList.getParameter(0)?.type == field.type && parameterList.getParametersCount() == 1
 }
 
-internal fun Visibility.isPublicAPI() = when(this) {
+private fun Visibility.isPublicAPI() = when(this) {
     KotlinVisibility.Public,
     KotlinVisibility.Protected,
     JavaVisibility.Public,
diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt
new file mode 100644
index 00000000000..f156ae5d94d
--- /dev/null
+++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt
@@ -0,0 +1,50 @@
+package org.jetbrains.dokka.analysis.java.util
+
+import com.intellij.psi.JavaDocTokenType
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiJavaCodeReferenceElement
+import com.intellij.psi.PsiWhiteSpace
+import com.intellij.psi.impl.source.tree.JavaDocElementType
+import com.intellij.psi.javadoc.PsiDocComment
+import com.intellij.psi.javadoc.PsiDocTag
+import com.intellij.psi.javadoc.PsiDocToken
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.dokka.analysis.java.DescriptionJavadocTag
+import org.jetbrains.dokka.analysis.java.JavadocTag
+import org.jetbrains.dokka.analysis.java.parsers.resolveToGetDri
+
+internal fun PsiDocComment.hasTag(tag: JavadocTag): Boolean =
+    when (tag) {
+        DescriptionJavadocTag -> descriptionElements.isNotEmpty()
+        else -> findTagByName(tag.name) != null
+    }
+
+internal fun PsiDocTag.contentElementsWithSiblingIfNeeded(): List = if (dataElements.isNotEmpty()) {
+    listOfNotNull(
+        dataElements[0],
+        dataElements[0].nextSibling?.takeIf { it.text != dataElements.drop(1).firstOrNull()?.text },
+        *dataElements.drop(1).toTypedArray()
+    )
+} else {
+    emptyList()
+}
+
+internal fun PsiDocTag.resolveToElement(): PsiElement? =
+    dataElements.firstOrNull()?.firstChild?.referenceElementOrSelf()?.resolveToGetDri()
+
+internal fun PsiDocTag.referenceElement(): PsiElement? =
+    linkElement()?.referenceElementOrSelf()
+
+internal fun PsiElement.referenceElementOrSelf(): PsiElement? =
+    if (node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) {
+        PsiTreeUtil.findChildOfType(this, PsiJavaCodeReferenceElement::class.java)
+    } else this
+
+internal fun PsiDocTag.linkElement(): PsiElement? =
+    valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
+
+internal fun PsiElement.defaultLabel() = children.firstOrNull {
+    it is PsiDocToken && it.text.isNotBlank() && !it.isSharpToken()
+} ?: this
+
+internal fun PsiDocToken.isSharpToken() = tokenType == JavaDocTokenType.DOC_TAG_VALUE_SHARP_TOKEN
diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt
new file mode 100644
index 00000000000..9d5b0f5a96c
--- /dev/null
+++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt
@@ -0,0 +1,119 @@
+package org.jetbrains.dokka.analysis.java.util
+
+import com.intellij.psi.*
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.links.*
+import org.jetbrains.dokka.model.DocumentableSource
+
+// TODO [beresnev] copy-paste
+
+internal val PsiElement.parentsWithSelf: Sequence
+    get() = generateSequence(this) { if (it is PsiFile) null else it.parent }
+
+internal fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run {
+    val psiMethod = filterIsInstance().firstOrNull()
+    val psiField = filterIsInstance().firstOrNull()
+    val classes = filterIsInstance().filterNot { it is PsiTypeParameter }
+        .toList() // We only want exact PsiClass types, not PsiTypeParameter subtype
+    val additionalClasses = if (psi is PsiEnumConstant) listOfNotNull(psiField?.name) else emptyList()
+    DRI(
+        packageName = classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', "") ?: "",
+        classNames = (additionalClasses + classes.mapNotNull { it.name }).takeIf { it.isNotEmpty() }
+            ?.asReversed()?.joinToString("."),
+        // The fallback strategy test whether psi is not `PsiEnumConstant`. The reason behind this is that
+        // we need unified DRI for both Java and Kotlin enums, so we can link them properly and treat them alike.
+        // To achieve that, we append enum name to classNames list and leave the callable part set to null. For Kotlin enums
+        // it is by default, while for Java enums we have to explicitly test for that in this `takeUnless` condition.
+        callable = psiMethod?.let { Callable.from(it) } ?: psiField?.takeUnless { psi is PsiEnumConstant }?.let { Callable.from(it) },
+        target = DriTarget.from(psi),
+        extra = if (psi is PsiEnumConstant)
+            DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
+        else null
+    )
+}
+
+internal fun Callable.Companion.from(psi: PsiMethod) = with(psi) {
+    Callable(
+        name,
+        null,
+        parameterList.parameters.map { param -> JavaClassReference(param.type.canonicalText) })
+}
+
+internal fun Callable.Companion.from(psi: PsiField): Callable {
+    return Callable(
+        name = psi.name,
+        receiver = null,
+        params = emptyList()
+    )
+}
+
+internal fun DriTarget.Companion.from(psi: PsiElement): DriTarget = psi.parentsWithSelf.run {
+    return when (psi) {
+        is PsiTypeParameter -> PointingToGenericParameters(psi.index)
+        else -> filterIsInstance().firstOrNull()?.let {
+            val callable = filterIsInstance().firstOrNull()
+            val params = (callable?.parameterList?.parameters).orEmpty()
+            PointingToCallableParameters(params.indexOf(it))
+        } ?: PointingToDeclaration
+    }
+}
+
+// TODO [beresnev] copy-paste
+internal fun PsiElement.siblings(forward: Boolean = true, withItself: Boolean = true): Sequence {
+    return object : Sequence {
+        override fun iterator(): Iterator {
+            var next: PsiElement? = this@siblings
+            return object : Iterator {
+                init {
+                    if (!withItself) next()
+                }
+
+                override fun hasNext(): Boolean = next != null
+                override fun next(): PsiElement {
+                    val result = next ?: throw NoSuchElementException()
+                    next = if (forward) result.nextSibling else result.prevSibling
+                    return result
+                }
+            }
+        }
+    }
+}
+
+// TODO [beresnev] copy-paste
+internal fun PsiElement.getNextSiblingIgnoringWhitespace(withItself: Boolean = false): PsiElement? {
+    return siblings(withItself = withItself).filter { it !is PsiWhiteSpace }.firstOrNull()
+}
+
+@InternalDokkaApi
+class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource {
+    override val path = psi.containingFile.virtualFile.path
+
+    override val lineNumber: Int?
+        get() = this.psi.let {
+            val range = it.getChildOfType()?.textRange ?: it.textRange
+            val doc = PsiDocumentManager.getInstance(it.project).getDocument(it.containingFile)
+            // IJ uses 0-based line-numbers; external source browsers use 1-based
+            return doc?.getLineNumber(range.startOffset)?.plus(1)
+        }
+}
+
+inline fun  PsiElement.getChildOfType(): T? {
+    return PsiTreeUtil.getChildOfType(this, T::class.java)
+}
+
+internal fun PsiElement.getKotlinFqName(): String? = this.kotlinFqNameProp
+
+//// from import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
+internal val PsiElement.kotlinFqNameProp: String?
+    get() = when (val element = this) {
+        is PsiPackage -> element.qualifiedName
+        is PsiClass -> element.qualifiedName
+        is PsiMember -> element.name?.let { name ->
+            val prefix = element.containingClass?.qualifiedName
+            if (prefix != null) "$prefix.$name" else name
+        }
+//        is KtNamedDeclaration -> element.fqName TODO [beresnev] decide what to do with it
+        is PsiQualifiedNamedElement -> element.qualifiedName
+        else -> null
+    }
diff --git a/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt
new file mode 100644
index 00000000000..cce76ce6ed2
--- /dev/null
+++ b/analysis/java-analysis-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt
@@ -0,0 +1,33 @@
+package org.jetbrains.dokka.analysis.java.util
+
+import java.util.*
+
+// TODO [beresnev] copy-paste
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun  Iterable.firstNotNullOfOrNull(transform: (T) -> R?): R? {
+    for (element in this) {
+        val result = transform(element)
+        if (result != null) {
+            return result
+        }
+    }
+    return null
+}
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun Char.uppercaseChar(): Char = Character.toUpperCase(this)
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun Char.lowercaseChar(): Char = Character.toLowerCase(this)
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun String.lowercase(): String = this.toLowerCase(Locale.ROOT)
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun String.uppercase(): String = this.toUpperCase(Locale.ROOT)
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal fun String.replaceFirstChar(transform: (Char) -> Char): String {
+    return if (isNotEmpty()) transform(this[0]) + substring(1) else this
+}
diff --git a/analysis/java-analysis-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/analysis/java-analysis-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000000..51d36899b60
--- /dev/null
+++ b/analysis/java-analysis-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin
diff --git a/analysis/kotlin-analysis-api/api/kotlin-analysis-api.api b/analysis/kotlin-analysis-api/api/kotlin-analysis-api.api
new file mode 100644
index 00000000000..78080880ae3
--- /dev/null
+++ b/analysis/kotlin-analysis-api/api/kotlin-analysis-api.api
@@ -0,0 +1,66 @@
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/DocumentableAnalyzer {
+	public abstract fun getLanguage (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage;
+}
+
+public final class org/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage : java/lang/Enum {
+	public static final field JAVA Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage;
+	public static final field KOTLIN Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage;
+	public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage;
+	public static fun values ()[Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableLanguage;
+}
+
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/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/kotlin/analysis/kotlin/FullClassHierarchyBuilder {
+	public abstract fun build (Lorg/jetbrains/dokka/model/DModule;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+}
+
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/InheritanceBuilder {
+	public abstract fun build (Ljava/util/Map;)Ljava/util/List;
+}
+
+public final class org/jetbrains/kotlin/analysis/kotlin/InheritanceNode {
+	public fun  (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Z)V
+	public synthetic fun  (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun component1 ()Lorg/jetbrains/dokka/links/DRI;
+	public final fun component2 ()Ljava/util/List;
+	public final fun component3 ()Ljava/util/List;
+	public final fun component4 ()Z
+	public final fun copy (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Z)Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceNode;
+	public static synthetic fun copy$default (Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceNode;Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;ZILjava/lang/Object;)Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceNode;
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getChildren ()Ljava/util/List;
+	public final fun getDri ()Lorg/jetbrains/dokka/links/DRI;
+	public final fun getInterfaces ()Ljava/util/List;
+	public fun hashCode ()I
+	public final fun isInterface ()Z
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class org/jetbrains/kotlin/analysis/kotlin/KotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+	public fun  ()V
+	public final fun getDocumentableAnalyzer ()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 getKotlinToJavaMapper ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getModuleAndPackageDocumentationReader ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getSyntheticDocumentableDetector ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+}
+
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/KotlinToJavaMapper {
+	public abstract fun findAsJava (Lorg/jetbrains/dokka/links/DRI;)Lorg/jetbrains/dokka/links/DRI;
+}
+
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/ModuleAndPackageDocumentationReader {
+	public abstract fun read (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaModuleDescription;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
+	public abstract fun read (Lorg/jetbrains/dokka/model/DModule;)Ljava/util/Map;
+	public abstract fun read (Lorg/jetbrains/dokka/model/DPackage;)Ljava/util/Map;
+}
+
+public abstract interface class org/jetbrains/kotlin/analysis/kotlin/SyntheticDocumentableDetector {
+	public abstract fun isSynthetic (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Z
+}
+
diff --git a/analysis/kotlin-analysis-api/build.gradle.kts b/analysis/kotlin-analysis-api/build.gradle.kts
new file mode 100644
index 00000000000..f49833a590c
--- /dev/null
+++ b/analysis/kotlin-analysis-api/build.gradle.kts
@@ -0,0 +1,14 @@
+import org.jetbrains.registerDokkaArtifactPublication
+
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+    id("org.jetbrains.conventions.maven-publish")
+}
+
+dependencies {
+    compileOnly(projects.core)
+}
+
+registerDokkaArtifactPublication("kotlinAnalysisApi") {
+    artifactId = "kotlin-analysis-api"
+}
diff --git a/analysis/kotlin-analysis-api/src/main/kotlin/org/jetbrains/kotlin/analysis/kotlin/KotlinAnalysisPlugin.kt b/analysis/kotlin-analysis-api/src/main/kotlin/org/jetbrains/kotlin/analysis/kotlin/KotlinAnalysisPlugin.kt
new file mode 100644
index 00000000000..335883b0e90
--- /dev/null
+++ b/analysis/kotlin-analysis-api/src/main/kotlin/org/jetbrains/kotlin/analysis/kotlin/KotlinAnalysisPlugin.kt
@@ -0,0 +1,90 @@
+package org.jetbrains.kotlin.analysis.kotlin
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.doc.DocumentationNode
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
+
+typealias Supertypes = List
+typealias ClassHierarchy = SourceSetDependent>
+
+interface FullClassHierarchyBuilder {
+    suspend fun build(module: DModule): ClassHierarchy
+}
+
+data class InheritanceNode(
+    val dri: DRI,
+    val children: List = emptyList(),
+    val interfaces: List = emptyList(),
+    val isInterface: Boolean = false
+) {
+    override fun equals(other: Any?): Boolean = other is InheritanceNode && other.dri == dri
+    override fun hashCode(): Int = dri.hashCode()
+}
+
+interface InheritanceBuilder {
+    fun build(documentables: Map): List
+}
+
+// TODO [beresnev] isSynthetic could be a property of Documentable?
+interface SyntheticDocumentableDetector {
+    fun isSynthetic(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean
+}
+
+interface ModuleAndPackageDocumentationReader {
+    fun read(module: DModule): SourceSetDependent
+    fun read(pkg: DPackage): SourceSetDependent
+    fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode?
+}
+
+interface KotlinToJavaMapper {
+    fun findAsJava(kotlinDri: DRI): DRI?
+}
+
+/**
+ * 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).
+ */
+fun interface ExternalDocumentablesProvider {
+
+    /**
+     * Returns [DClasslike] matching provided [DRI] in specified source set.
+     *
+     * Result is null if compiler haven't generated matching class descriptor.
+     */
+    fun findClasslike(dri: DRI, sourceSet: DokkaConfiguration.DokkaSourceSet): DClasslike?
+}
+
+interface DocumentableAnalyzer {
+    fun getLanguage(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): DocumentableLanguage?
+}
+
+enum class DocumentableLanguage {
+    JAVA, KOTLIN
+}
+
+class KotlinAnalysisPlugin : DokkaPlugin() {
+
+    val fullClassHierarchyBuilder by extensionPoint()
+
+    val syntheticDocumentableDetector by extensionPoint()
+
+    val moduleAndPackageDocumentationReader by extensionPoint()
+
+    val kotlinToJavaMapper by extensionPoint()
+
+    val inheritanceBuilder by extensionPoint()
+
+    val externalDocumentablesProvider by extensionPoint()
+
+    val documentableAnalyzer by extensionPoint()
+
+    @OptIn(DokkaPluginApiPreview::class)
+    override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/analysis/kotlin-analysis-descriptors/build.gradle.kts b/analysis/kotlin-analysis-descriptors/build.gradle.kts
new file mode 100644
index 00000000000..5cbea2cd7b1
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/build.gradle.kts
@@ -0,0 +1,31 @@
+import org.jetbrains.DokkaPublicationBuilder
+import org.jetbrains.registerDokkaArtifactPublication
+
+plugins {
+    id("org.jetbrains.conventions.base-java")
+    id("org.jetbrains.conventions.maven-publish")
+    id("com.github.johnrengelman.shadow")
+}
+
+dependencies {
+    implementation(projects.analysis.kotlinAnalysisApi)
+    implementation(projects.analysis.kotlinAnalysisDescriptors.compiler)
+    implementation(projects.analysis.kotlinAnalysisDescriptors.ide)
+}
+
+tasks {
+    shadowJar {
+        val dokka_version: String by project
+        archiveFileName.set("dokka-analysis-descriptors-$dokka_version.jar")
+        archiveClassifier.set("")
+
+        // service files are merged to make sure all Dokka plugins
+        // from the dependencies are loaded, and not just a single one.
+        mergeServiceFiles()
+    }
+}
+
+registerDokkaArtifactPublication("kotlinAnalysisDescriptors") {
+    artifactId = "kotlin-analysis-descriptors"
+    component = DokkaPublicationBuilder.Component.Shadow
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/api/compiler.api b/analysis/kotlin-analysis-descriptors/compiler/api/compiler.api
new file mode 100644
index 00000000000..06dc6efc41c
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/api/compiler.api
@@ -0,0 +1,68 @@
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/AnalysisContextCreator {
+	public abstract fun create (Lcom/intellij/mock/MockProject;Lorg/jetbrains/kotlin/descriptors/ModuleDescriptor;Lorg/jetbrains/kotlin/analyzer/ResolverForModule;Lorg/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment;)Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext;
+}
+
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+	public fun  ()V
+	public final fun getAnalysisContextCreator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getCompilerExtensionPointProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getKdocFinder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getKlibService ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getKotlinAnalysis ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getMockApplicationHack ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+	public final fun getSearchHelpers ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider {
+	public abstract fun get ()Ljava/util/List;
+}
+
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider$CompilerExtensionPoint {
+	public fun  (Lorg/jetbrains/kotlin/extensions/ApplicationExtensionDescriptor;Ljava/util/List;)V
+	public final fun getExtensionDescriptor ()Lorg/jetbrains/kotlin/extensions/ApplicationExtensionDescriptor;
+	public final fun getExtensions ()Ljava/util/List;
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder {
+	public abstract fun find (Lorg/jetbrains/kotlin/descriptors/DeclarationDescriptor;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/kotlin/kdoc/psi/impl/KDocTag;
+	public abstract fun findKDoc (Lorg/jetbrains/kotlin/psi/KtElement;)Lorg/jetbrains/kotlin/kdoc/psi/impl/KDocTag;
+	public abstract fun resolveKDocLink (Lorg/jetbrains/kotlin/descriptors/DeclarationDescriptor;Ljava/lang/String;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Z)Ljava/util/Collection;
+}
+
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder$DefaultImpls {
+	public static synthetic fun find$default (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder;Lorg/jetbrains/kotlin/descriptors/DeclarationDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/jetbrains/kotlin/kdoc/psi/impl/KDocTag;
+	public static synthetic fun resolveKDocLink$default (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder;Lorg/jetbrains/kotlin/descriptors/DeclarationDescriptor;Ljava/lang/String;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;ZILjava/lang/Object;)Ljava/util/Collection;
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService {
+	public abstract fun createPackageFragmentProvider (Lorg/jetbrains/kotlin/library/KotlinLibrary;Lorg/jetbrains/kotlin/storage/StorageManager;Lorg/jetbrains/kotlin/backend/common/serialization/metadata/KlibMetadataModuleDescriptorFactory;Lorg/jetbrains/kotlin/config/LanguageVersionSettings;Lorg/jetbrains/kotlin/descriptors/ModuleDescriptor;Lorg/jetbrains/kotlin/incremental/components/LookupTracker;)Lorg/jetbrains/kotlin/descriptors/PackageFragmentProvider;
+	public abstract fun isAnalysisCompatible (Lorg/jetbrains/kotlin/library/KotlinLibrary;)Z
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack {
+	public abstract fun hack (Lcom/intellij/mock/MockApplication;)V
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/SearchHelpers {
+	public abstract fun findDescriptor (Lorg/jetbrains/kotlin/psi/KtDeclaration;)Lorg/jetbrains/kotlin/descriptors/DeclarationDescriptor;
+}
+
+public abstract interface class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext : java/io/Closeable {
+	public abstract fun getEnvironment ()Lorg/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment;
+	public abstract fun getModuleDescriptor ()Lorg/jetbrains/kotlin/descriptors/ModuleDescriptor;
+	public abstract fun getProject ()Lcom/intellij/openapi/project/Project;
+	public abstract fun getResolveSession ()Lorg/jetbrains/kotlin/resolve/lazy/ResolveSession;
+}
+
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment : com/intellij/openapi/Disposable {
+	public fun  (Lorg/jetbrains/kotlin/cli/common/messages/MessageCollector;Lorg/jetbrains/dokka/Platform;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService;)V
+	public fun dispose ()V
+}
+
+public abstract class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis : java/io/Closeable {
+	public fun  ()V
+	public fun  (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis;)V
+	public synthetic fun  (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun get (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext;
+}
+
diff --git a/analysis/kotlin-analysis-descriptors/compiler/build.gradle.kts b/analysis/kotlin-analysis-descriptors/compiler/build.gradle.kts
new file mode 100644
index 00000000000..a68e43de35b
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/build.gradle.kts
@@ -0,0 +1,21 @@
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+}
+
+dependencies {
+    compileOnly(projects.core)
+    compileOnly(projects.analysis.kotlinAnalysisApi)
+
+    api(libs.kotlin.compiler)
+
+    implementation(projects.analysis.markdown)
+    implementation(projects.analysis.javaAnalysisPsi)
+
+    testImplementation(projects.core.contentMatcherTestUtils)
+    testImplementation(projects.core.testApi)
+    testImplementation(platform(libs.junit.bom))
+    testImplementation(libs.junit.jupiter)
+
+    // TODO [beresnev] get rid of it
+    compileOnly(libs.kotlinx.coroutines.core)
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt
new file mode 100644
index 00000000000..70344817bb2
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt
@@ -0,0 +1,233 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler
+
+import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute
+import com.intellij.mock.MockApplication
+import com.intellij.mock.MockProject
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiElement
+import org.jetbrains.dokka.CoreExtensions
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.analysis.java.BreakingAbstractionKotlinLightMethodChecker
+import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin
+import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentationReader
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DefaultDescriptorToDocumentableTranslator
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.DefaultExternalDocumentablesProvider
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.WithSources
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.renderers.PostAction
+import org.jetbrains.kotlin.analysis.kotlin.DocumentableAnalyzer
+import org.jetbrains.kotlin.analysis.kotlin.DocumentableLanguage
+import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin
+import org.jetbrains.kotlin.analyzer.ResolverForModule
+import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
+import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
+import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.storage.StorageManager
+
+@InternalDokkaApi
+interface KDocFinder {
+    fun KtElement.findKDoc(): KDocTag?
+
+    fun DeclarationDescriptor.find(
+        descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { DescriptorToSourceUtils.descriptorToDeclaration(it) }
+    ): KDocTag?
+
+    fun resolveKDocLink(
+        fromDescriptor: DeclarationDescriptor,
+        qualifiedName: String,
+        sourceSet: DokkaConfiguration.DokkaSourceSet,
+        emptyBindingContext: Boolean = false
+    ): Collection
+}
+
+@InternalDokkaApi
+interface SearchHelpers {
+    fun KtDeclaration.findDescriptor(): DeclarationDescriptor?
+}
+
+@InternalDokkaApi
+interface KLibService {
+    fun KotlinLibrary.createPackageFragmentProvider(
+        storageManager: StorageManager,
+        metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory,
+        languageVersionSettings: LanguageVersionSettings,
+        moduleDescriptor: ModuleDescriptor,
+        lookupTracker: LookupTracker
+    ): PackageFragmentProvider?
+
+    fun isAnalysisCompatible(kotlinLibrary: KotlinLibrary): Boolean
+}
+
+@InternalDokkaApi
+interface CompilerExtensionPointProvider {
+    fun get(): List
+
+    class CompilerExtensionPoint(
+        val extensionDescriptor: ApplicationExtensionDescriptor,
+        val extensions: List
+    )
+}
+
+@InternalDokkaApi
+interface MockApplicationHack {
+    fun hack(mockApplication: MockApplication)
+}
+
+@InternalDokkaApi
+interface AnalysisContextCreator {
+    fun create(
+        project: MockProject,
+        moduleDescriptor: ModuleDescriptor,
+        moduleResolver: ResolverForModule,
+        kotlinEnvironment: KotlinCoreEnvironment,
+        analysisEnvironment: AnalysisEnvironment,
+    ): AnalysisContext
+}
+
+internal class DocumentableAnalyzerImpl : DocumentableAnalyzer {
+    override fun getLanguage(
+        documentable: Documentable,
+        sourceSet: DokkaConfiguration.DokkaSourceSet,
+    ): DocumentableLanguage? {
+        val documentableSource = (documentable as? WithSources)?.sources?.get(sourceSet) ?: return null
+        return when (documentableSource) {
+            is PsiDocumentableSource -> DocumentableLanguage.JAVA
+            is DescriptorDocumentableSource -> DocumentableLanguage.KOTLIN
+            else -> error("Unknown language sources: ${documentableSource::class}")
+        }
+    }
+}
+
+@InternalDokkaApi
+class CompilerDescriptorAnalysisPlugin : DokkaPlugin() {
+
+    val kdocFinder by extensionPoint()
+
+    val searchHelpers by extensionPoint()
+
+    val klibService by extensionPoint()
+
+    val compilerExtensionPointProvider by extensionPoint()
+
+    val mockApplicationHack by extensionPoint()
+
+    val analysisContextCreator by extensionPoint()
+
+    val kotlinAnalysis by extensionPoint()
+
+    internal val documentableAnalyzerImpl by extending {
+        plugin().documentableAnalyzer providing { DocumentableAnalyzerImpl() }
+    }
+
+    internal  val defaultKotlinAnalysis by extending {
+        kotlinAnalysis providing { ctx ->
+            ProjectKotlinAnalysis(
+                sourceSets = ctx.configuration.sourceSets,
+                context = ctx
+            )
+        }
+    }
+
+    internal  val descriptorToDocumentableTranslator by extending {
+        CoreExtensions.sourceToDocumentableTranslator providing ::DefaultDescriptorToDocumentableTranslator
+    }
+
+    internal val defaultSamplesTransformer by extending {
+        CoreExtensions.pageTransformer providing ::DefaultSamplesTransformer
+    }
+
+    internal val descriptorFullClassHierarchyBuilder by extending {
+        plugin().fullClassHierarchyBuilder providing { DescriptorFullClassHierarchyBuilder() }
+    }
+
+    internal val descriptorSyntheticDocumentableDetector by extending {
+        plugin().syntheticDocumentableDetector providing { DescriptorSyntheticDocumentableDetector() }
+    }
+
+    internal val moduleAndPackageDocumentationReader by extending {
+        plugin().moduleAndPackageDocumentationReader providing ::ModuleAndPackageDocumentationReader
+    }
+
+    internal val kotlinToJavaMapper by extending {
+        plugin().kotlinToJavaMapper providing { DescriptorKotlinToJavaMapper() }
+    }
+
+    internal val descriptorInheritanceBuilder by extending {
+        plugin().inheritanceBuilder providing { DescriptorInheritanceBuilder() }
+    }
+
+    internal val defaultExternalDocumentablesProvider by extending {
+        plugin().externalDocumentablesProvider providing ::DefaultExternalDocumentablesProvider
+    }
+
+    private val javaAnalysisPlugin by lazy { plugin() }
+
+    internal val projectProvider by extending {
+        javaAnalysisPlugin.projectProvider providing { KotlinAnalysisProjectProvider() }
+    }
+
+    internal val sourceRootsExtractor by extending {
+        javaAnalysisPlugin.sourceRootsExtractor providing { KotlinAnalysisSourceRootsExtractor() }
+    }
+
+    internal val kotlinDocCommentCreator by extending {
+        javaAnalysisPlugin.docCommentCreators providing {
+            KotlinDocCommentCreator(querySingle { kdocFinder }, querySingle { searchHelpers })
+        }
+    }
+
+    internal val kotlinDocCommentParser by extending {
+        javaAnalysisPlugin.docCommentParsers providing { context ->
+            KotlinDocCommentParser(
+                context,
+                context.logger
+            )
+        }
+    }
+
+    internal val inheritDocTagProvider by extending {
+        javaAnalysisPlugin.inheritDocTagContentProviders providing ::KotlinInheritDocTagContentProvider
+    }
+
+    internal val kotlinLightMethodChecker by extending {
+        javaAnalysisPlugin.kotlinLightMethodChecker providing {
+            object : BreakingAbstractionKotlinLightMethodChecker {
+                override fun isLightAnnotation(annotation: PsiAnnotation): Boolean {
+                    return annotation is KtLightAbstractAnnotation
+                }
+
+                override fun isLightAnnotationAttribute(attribute: JvmAnnotationAttribute): Boolean {
+                    return attribute is KtLightAbstractAnnotation
+                }
+            }
+        }
+    }
+
+    internal val disposeKotlinAnalysisPostAction by extending {
+        CoreExtensions.postActions with PostAction { querySingle { kotlinAnalysis }.close() }
+    }
+
+    @OptIn(DokkaPluginApiPreview::class)
+    override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt
new file mode 100644
index 00000000000..f1d35752075
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt
@@ -0,0 +1,3 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
+
+internal typealias AbsolutePathString = String
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisContext.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt
similarity index 59%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisContext.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt
index ca83d02948c..89ae8810fd8 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisContext.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt
@@ -1,18 +1,26 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
+import com.intellij.openapi.project.Project
 import org.jetbrains.dokka.DokkaConfiguration
 import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.AnalysisContextCreator
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.utilities.DokkaLogger
 import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
 import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
 import org.jetbrains.kotlin.cli.common.messages.MessageCollector
 import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
 import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
 import java.io.Closeable
 import java.io.File
 
 internal fun createAnalysisContext(
-    logger: DokkaLogger,
+    context: DokkaContext,
     sourceSets: List,
     sourceSet: DokkaConfiguration.DokkaSourceSet,
     analysisConfiguration: DokkaAnalysisConfiguration
@@ -22,7 +30,7 @@ internal fun createAnalysisContext(
     val sources = sourceSet.sourceRoots + parentSourceSets.flatMap { it.sourceRoots }
 
     return createAnalysisContext(
-        logger = logger,
+        context = context,
         classpath = classpath,
         sourceRoots = sources,
         sourceSet = sourceSet,
@@ -31,13 +39,19 @@ internal fun createAnalysisContext(
 }
 
 internal fun createAnalysisContext(
-    logger: DokkaLogger,
+    context: DokkaContext,
     classpath: List,
     sourceRoots: Set,
     sourceSet: DokkaConfiguration.DokkaSourceSet,
     analysisConfiguration: DokkaAnalysisConfiguration
 ): AnalysisContext {
-    val analysisEnvironment = AnalysisEnvironment(DokkaMessageCollector(logger), sourceSet.analysisPlatform).apply {
+    val analysisEnvironment = AnalysisEnvironment(
+        DokkaMessageCollector(context.logger),
+        sourceSet.analysisPlatform,
+        context.plugin().querySingle { compilerExtensionPointProvider },
+        context.plugin().querySingle { mockApplicationHack },
+        context.plugin().querySingle { klibService },
+    ).apply {
         if (analysisPlatform == Platform.jvm) {
             configureJdkClasspathRoots()
         }
@@ -48,15 +62,14 @@ internal fun createAnalysisContext(
     }
 
     val environment = analysisEnvironment.createCoreEnvironment()
-    val (facade, _) = analysisEnvironment.createResolutionFacade(
+    return analysisEnvironment.createResolutionFacade(
         environment,
+        context.plugin().querySingle { analysisContextCreator },
         analysisConfiguration.ignoreCommonBuiltIns
     )
-
-    return AnalysisContext(environment, facade, analysisEnvironment)
 }
 
-class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector {
+internal class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector {
     override fun clear() {
         seenErrors = false
     }
@@ -73,22 +86,9 @@ class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector
     override fun hasErrors() = seenErrors
 }
 
-// It is not data class due to ill-defined equals
-class AnalysisContext(
-    environment: KotlinCoreEnvironment,
-    facade: DokkaResolutionFacade,
-    private val analysisEnvironment: AnalysisEnvironment
-) : Closeable {
-    private var isClosed: Boolean = false
-    val environment: KotlinCoreEnvironment = environment
-        get() = field.takeUnless { isClosed } ?: throw IllegalStateException("AnalysisEnvironment is already closed")
-    val facade: DokkaResolutionFacade = facade
-        get() = field.takeUnless { isClosed } ?: throw IllegalStateException("AnalysisEnvironment is already closed")
-
-    operator fun component1() = environment
-    operator fun component2() = facade
-    override fun close() {
-        isClosed = true
-        analysisEnvironment.dispose()
-    }
+interface AnalysisContext : Closeable {
+    val environment: KotlinCoreEnvironment
+    val resolveSession: ResolveSession
+    val moduleDescriptor: ModuleDescriptor
+    val project: Project
 }
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt
similarity index 87%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt
index bbc6dda648d..db20498d1be 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AnalysisEnvironment.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt
@@ -1,8 +1,9 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.core.CoreApplicationEnvironment
 import com.intellij.mock.MockApplication
 import com.intellij.mock.MockComponentManager
+import com.intellij.mock.MockProject
 import com.intellij.openapi.Disposable
 import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.extensions.Extensions
@@ -16,14 +17,21 @@ import com.intellij.psi.javadoc.CustomJavadocTagProvider
 import com.intellij.psi.javadoc.JavadocManager
 import com.intellij.psi.javadoc.JavadocTagInfo
 import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.dokka.InternalDokkaApi
 import org.jetbrains.dokka.Platform
-import org.jetbrains.dokka.analysis.resolve.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.AnalysisContextCreator
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerExtensionPointProvider
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KLibService
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.MockApplicationHack
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve.*
 import org.jetbrains.kotlin.analyzer.*
-import org.jetbrains.kotlin.analyzer.common.*
+import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
+import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
+import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
+import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
 import org.jetbrains.kotlin.builtins.DefaultBuiltIns
 import org.jetbrains.kotlin.builtins.KotlinBuiltIns
 import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
-import org.jetbrains.kotlin.caches.resolve.*
 import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
 import org.jetbrains.kotlin.cli.common.config.ContentRoot
 import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
@@ -42,9 +50,6 @@ import org.jetbrains.kotlin.context.withModule
 import org.jetbrains.kotlin.descriptors.ModuleDescriptor
 import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
 import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
-import org.jetbrains.kotlin.ide.konan.NativePlatformKindResolution
-import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache
-import org.jetbrains.kotlin.idea.klib.getCompatibilityInfo
 import org.jetbrains.kotlin.js.config.JSConfigurationKeys
 import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
 import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
@@ -55,12 +60,7 @@ import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
 import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.platform.CommonPlatforms
-import org.jetbrains.kotlin.platform.IdePlatformKind
 import org.jetbrains.kotlin.platform.TargetPlatform
-import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
-import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
-import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
-import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
 import org.jetbrains.kotlin.platform.js.JsPlatforms
 import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
 import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.unspecifiedJvmPlatform
@@ -77,7 +77,7 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
 import java.io.File
 import org.jetbrains.kotlin.konan.file.File as KFile
 
-const val JAR_SEPARATOR = "!/"
+internal const val JAR_SEPARATOR = "!/"
 
 /**
  * Kotlin as a service entry point
@@ -87,14 +87,21 @@ const val JAR_SEPARATOR = "!/"
  * $messageCollector: required by compiler infrastructure and will receive all compiler messages
  * $body: optional and can be used to configure environment without creating local variable
  */
-class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPlatform: Platform) : Disposable {
-    val configuration = CompilerConfiguration()
+@InternalDokkaApi
+class AnalysisEnvironment(
+    private val messageCollector: MessageCollector,
+    internal val analysisPlatform: Platform,
+    private val compilerExtensionPointProvider: CompilerExtensionPointProvider,
+    private val mockApplicationHack: MockApplicationHack,
+    private val kLibService: KLibService,
+) : Disposable {
+    private val configuration = CompilerConfiguration()
 
     init {
         configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
     }
 
-    fun createCoreEnvironment(): KotlinCoreEnvironment {
+    internal fun createCoreEnvironment(): KotlinCoreEnvironment {
         System.setProperty("idea.io.use.nio2", "true")
         System.setProperty("idea.ignore.disabled.plugins", "true")
 
@@ -123,8 +130,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
         // TODO: figure out why compilation fails with unresolved `CoreApplicationEnvironment.registerApplicationService(...)`
         //  call, fix it appropriately
         with(ApplicationManager.getApplication() as MockApplication) {
-            if (getService(KlibLoadingMetadataCache::class.java) == null)
-                registerService(KlibLoadingMetadataCache::class.java, KlibLoadingMetadataCache())
+            mockApplicationHack.hack(this)
         }
 
         projectComponentManager.registerService(
@@ -142,28 +148,9 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
             CustomJavadocTagProvider { emptyList() }
         )
 
-        registerExtensionPoint(
-            ApplicationExtensionDescriptor("org.jetbrains.kotlin.idePlatformKind", IdePlatformKind::class.java),
-            listOf(
-                CommonIdePlatformKind,
-                JvmIdePlatformKind,
-                JsIdePlatformKind,
-                NativeIdePlatformKind
-            ),
-            this
-        )
-
-        registerExtensionPoint(
-            IdePlatformKindResolution,
-            listOf(
-                CommonPlatformKindResolution(),
-                JvmPlatformKindResolution(),
-                JsPlatformKindResolution(),
-                NativePlatformKindResolution()
-            ),
-            this
-        )
-
+        compilerExtensionPointProvider.get().forEach { extension ->
+            registerExtensionPoint(extension.extensionDescriptor, extension.extensions, this)
+        }
         return environment
     }
 
@@ -176,7 +163,11 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
             )
         }
 
-    fun createResolutionFacade(environment: KotlinCoreEnvironment, ignoreCommonBuiltIns: Boolean = false): Pair {
+    internal fun createResolutionFacade(
+        environment: KotlinCoreEnvironment,
+        analysisContextCreator: AnalysisContextCreator,
+        ignoreCommonBuiltIns: Boolean = false
+    ): AnalysisContext {
         val projectContext = ProjectContext(environment.project, "Dokka")
         val sourceFiles = environment.getSourceFiles()
 
@@ -269,33 +260,31 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
             Platform.native -> createNativeResolverForProject(projectContext, module, modulesContent)
 
         }
+        @Suppress("UNUSED_VARIABLE") // BEWARE!!!! IT's UNUSED, but without it some things don't work
         val libraryModuleDescriptor = resolverForProject.descriptorForModule(library)
+
         val moduleDescriptor = resolverForProject.descriptorForModule(module)
         builtIns?.initialize(moduleDescriptor, true)
 
-        val resolverForLibrary =
-            resolverForProject.resolverForModule(library) // Required before module to initialize library properly
+        @Suppress("UNUSED_VARIABLE") // BEWARE!!!! IT's UNUSED, but without it some things don't work
+        val resolverForLibrary = resolverForProject.resolverForModule(library) // Required before module to initialize library properly
+
         val resolverForModule = resolverForProject.resolverForModule(module)
-        val libraryResolutionFacade =
-            DokkaResolutionFacade(
-                environment.project,
-                libraryModuleDescriptor,
-                resolverForLibrary
-            )
-        val created =
-            DokkaResolutionFacade(
-                environment.project,
-                moduleDescriptor,
-                resolverForModule
-            )
-        val projectComponentManager = environment.project as MockComponentManager
-        projectComponentManager.registerService(
-            KotlinCacheService::
-            class.java,
-            CoreKotlinCacheService(created)
-        )
 
-        return created to libraryResolutionFacade
+//        val libraryResolutionFacade =
+//            DokkaResolutionFacade(
+//                environment.project,
+//                libraryModuleDescriptor,
+//                resolverForLibrary
+//            )
+
+        return analysisContextCreator.create(
+            environment.project as MockProject,
+            moduleDescriptor,
+            resolverForModule,
+            environment,
+            this
+        )
     }
 
     private fun Platform.analyzerServices() = when (this) {
@@ -305,7 +294,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
         Platform.jvm -> JvmPlatformAnalyzerServices
     }
 
-    fun Collection.registerLibraries(): List {
+    private fun Collection.registerLibraries(): List {
         if (analysisPlatform != Platform.native && analysisPlatform != Platform.js && analysisPlatform != Platform.wasm) return emptyList()
         val dependencyResolver = DokkaKlibLibraryDependencyResolver()
         val analyzerServices = analysisPlatform.analyzerServices()
@@ -331,8 +320,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
                             libraryFile = KFile(libraryFile.absolutePath),
                             strategy = ToolingSingleFileKlibResolveStrategy
                         )
-
-                        if (kotlinLibrary.getCompatibilityInfo().isCompatible) {
+                        if (kLibService.isAnalysisCompatible(kotlinLibrary)) {
                             // exists, is KLIB, has compatible format
                             put(
                                 libraryFile.absolutePath,
@@ -404,7 +392,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
             override fun createResolverForModule(
                 descriptor: ModuleDescriptor,
                 moduleInfo: ModuleInfo
-            ): ResolverForModule = DokkaJsResolverForModuleFactory(CompilerEnvironment).createResolverForModule(
+            ): ResolverForModule = DokkaJsResolverForModuleFactory(CompilerEnvironment, kLibService).createResolverForModule(
                 descriptor as ModuleDescriptorImpl,
                 projectContext.withModule(descriptor),
                 modulesContent(moduleInfo),
@@ -435,7 +423,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
                 moduleInfo: ModuleInfo
             ): ResolverForModule {
 
-                return DokkaNativeResolverForModuleFactory(CompilerEnvironment).createResolverForModule(
+                return DokkaNativeResolverForModuleFactory(CompilerEnvironment, kLibService).createResolverForModule(
                     descriptor as ModuleDescriptorImpl,
                     projectContext.withModule(descriptor),
                     modulesContent(moduleInfo),
@@ -518,7 +506,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
         }
     }
 
-    fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) {
+    internal fun loadLanguageVersionSettings(languageVersionString: String?, apiVersionString: String?) {
         val languageVersion = LanguageVersion.fromVersionString(languageVersionString) ?: LanguageVersion.LATEST_STABLE
         val apiVersion =
             apiVersionString?.let { ApiVersion.parse(it) } ?: ApiVersion.createByLanguageVersion(languageVersion)
@@ -534,7 +522,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
     /**
      * Classpath for this environment.
      */
-    val classpath: List
+    private val classpath: List
         get() = configuration.jvmClasspathRoots + configuration.getList(JSConfigurationKeys.LIBRARIES)
             .mapNotNull { File(it) }
 
@@ -542,7 +530,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
      * Adds list of paths to classpath.
      * $paths: collection of files to add
      */
-    fun addClasspath(paths: List) {
+    internal fun addClasspath(paths: List) {
         if (analysisPlatform == Platform.js || analysisPlatform == Platform.wasm) {
             configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath })
         } else {
@@ -551,12 +539,12 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
     }
 
     // Set up JDK classpath roots explicitly because of https://github.com/JetBrains/kotlin/commit/f89765eb33dd95c8de33a919cca83651b326b246
-    fun configureJdkClasspathRoots() = configuration.configureJdkClasspathRoots()
+    internal fun configureJdkClasspathRoots() = configuration.configureJdkClasspathRoots()
     /**
      * Adds path to classpath.
      * $path: path to add
      */
-    fun addClasspath(path: File) {
+    internal fun addClasspath(path: File) {
         if (analysisPlatform == Platform.js || analysisPlatform == Platform.wasm) {
             configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath)
         } else {
@@ -567,7 +555,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
     /**
      * List of source roots for this environment.
      */
-    val sources: List
+    internal val sources: List
         get() = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
             ?.filterIsInstance()
             ?.map { it.path } ?: emptyList()
@@ -576,7 +564,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
      * Adds list of paths to source roots.
      * $list: collection of files to add
      */
-    fun addSources(sourceDirectories: Iterable) {
+    internal fun addSources(sourceDirectories: Iterable) {
         sourceDirectories.forEach { directory ->
             configuration.addKotlinSourceRoot(directory.path)
             if (directory.isDirectory || directory.extension == "java") {
@@ -585,7 +573,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
         }
     }
 
-    fun addRoots(list: List) {
+    internal fun addRoots(list: List) {
         configuration.addAll(CLIConfigurationKeys.CONTENT_ROOTS, list)
     }
 
@@ -596,7 +584,7 @@ class AnalysisEnvironment(val messageCollector: MessageCollector, val analysisPl
         Disposer.dispose(this)
     }
 
-    companion object {
+    private companion object {
         private fun  registerExtensionPoint(
             appExtension: ApplicationExtensionDescriptor,
             instances: List,
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt
similarity index 68%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt
index de48cfae160..0cc17219391 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.psi.PsiField
 import com.intellij.psi.PsiMethod
@@ -7,7 +7,7 @@ import org.jetbrains.dokka.links.JavaClassReference
 import org.jetbrains.dokka.links.TypeReference
 import org.jetbrains.kotlin.descriptors.CallableDescriptor
 
-fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null) = with(descriptor) {
+internal fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null) = with(descriptor) {
     Callable(
         name ?: descriptor.name.asString(),
         extensionReceiverParameter?.let { TypeReference.from(it) },
@@ -15,14 +15,14 @@ fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null
     )
 }
 
-fun Callable.Companion.from(psi: PsiMethod) = with(psi) {
+internal fun Callable.Companion.from(psi: PsiMethod) = with(psi) {
     Callable(
         name,
         null,
         parameterList.parameters.map { param -> JavaClassReference(param.type.canonicalText) })
 }
 
-fun Callable.Companion.from(psi: PsiField): Callable {
+internal fun Callable.Companion.from(psi: PsiField): Callable {
     return Callable(
         name = psi.name,
         receiver = null,
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt
similarity index 74%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt
index 73b20885a5b..f0223cd079c 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.psi.*
 import org.jetbrains.dokka.links.*
@@ -6,30 +6,28 @@ 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
-import org.jetbrains.kotlin.utils.addToStdlib.safeAs
 
-fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run {
-    val parameter = firstIsInstanceOrNull()
-    val callable = parameter?.containingDeclaration ?: firstIsInstanceOrNull()
+internal fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run {
+    val parameter = filterIsInstance().firstOrNull()
+    val callable = parameter?.containingDeclaration ?: filterIsInstance().firstOrNull()
 
     DRI(
-        packageName = firstIsInstanceOrNull()?.fqName?.asString() ?: "",
+        packageName = filterIsInstance().firstOrNull()?.fqName?.asString() ?: "",
         classNames = (filterIsInstance() + filterIsInstance()).toList()
             .takeIf { it.isNotEmpty() }
             ?.asReversed()
             ?.joinToString(separator = ".") { it.name.asString() },
         callable = callable?.let { Callable.from(it) },
         target = DriTarget.from(parameter ?: descriptor),
-        extra = if (descriptor is EnumEntrySyntheticClassDescriptor || descriptor.safeAs()?.kind == ClassKind.ENUM_ENTRY)
+        extra = if (descriptor is EnumEntrySyntheticClassDescriptor || (descriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_ENTRY)
             DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode()
         else null
     )
 }
 
-fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run {
-    val psiMethod = firstIsInstanceOrNull()
-    val psiField = firstIsInstanceOrNull()
+internal fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run {
+    val psiMethod = filterIsInstance().firstOrNull()
+    val psiField = filterIsInstance().firstOrNull()
     val classes = filterIsInstance().filterNot { it is PsiTypeParameter }
         .toList() // We only want exact PsiClass types, not PsiTypeParameter subtype
     val additionalClasses = if (psi is PsiEnumConstant) listOfNotNull(psiField?.name) else emptyList()
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt
similarity index 68%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt
index e1e93962a6e..d46ee0c5c80 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRITargetFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.psi.PsiElement
 import com.intellij.psi.PsiMethod
@@ -11,17 +11,16 @@ import org.jetbrains.dokka.links.PointingToGenericParameters
 import org.jetbrains.kotlin.descriptors.*
 import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
 import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
-import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
 
-fun DriTarget.Companion.from(descriptor: DeclarationDescriptor): DriTarget = descriptor.parentsWithSelf.run {
+internal fun DriTarget.Companion.from(descriptor: DeclarationDescriptor): DriTarget = descriptor.parentsWithSelf.run {
     return when (descriptor) {
         is TypeParameterDescriptor -> PointingToGenericParameters(descriptor.index)
         is ValueParameterDescriptor -> PointingToCallableParameters(descriptor.index)
         else -> {
-            val callable = firstIsInstanceOrNull()
+            val callable = filterIsInstance().firstOrNull()
             val params =
                 callable?.let { listOfNotNull(it.extensionReceiverParameter) + it.valueParameters }.orEmpty()
-            val parameterDescriptor = firstIsInstanceOrNull()
+            val parameterDescriptor = filterIsInstance().firstOrNull()
 
             parameterDescriptor?.let { PointingToCallableParameters(params.indexOf(it)) }
                 ?: PointingToDeclaration
@@ -30,11 +29,11 @@ fun DriTarget.Companion.from(descriptor: DeclarationDescriptor): DriTarget = des
 }
 
 
-fun DriTarget.Companion.from(psi: PsiElement): DriTarget = psi.parentsWithSelf.run {
+internal fun DriTarget.Companion.from(psi: PsiElement): DriTarget = psi.parentsWithSelf.run {
     return when (psi) {
         is PsiTypeParameter -> PointingToGenericParameters(psi.index)
-        else -> firstIsInstanceOrNull()?.let {
-            val callable = firstIsInstanceOrNull()
+        else -> filterIsInstance().firstOrNull()?.let {
+            val callable = filterIsInstance().firstOrNull()
             val params = (callable?.parameterList?.parameters).orEmpty()
             PointingToCallableParameters(params.indexOf(it))
         } ?: PointingToDeclaration
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt
new file mode 100644
index 00000000000..e573a1ad8ba
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt
@@ -0,0 +1,23 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
+
+import com.intellij.psi.PsiDocumentManager
+import org.jetbrains.dokka.model.DocumentableSource
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.load.kotlin.toSourceElement
+import org.jetbrains.kotlin.resolve.source.getPsi
+
+internal class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource {
+    override val path = descriptor.toSourceElement.containingFile.toString()
+
+    override val lineNumber: Int?
+        get() = (this.descriptor as DeclarationDescriptorWithSource)
+            .source.getPsi()
+            ?.let {
+                val range = it.node?.findChildByType(KtTokens.IDENTIFIER)?.textRange ?: it.textRange
+                val doc = PsiDocumentManager.getInstance(it.project).getDocument(it.containingFile)
+                // IJ uses 0-based line-numbers; external source browsers use 1-based
+                doc?.getLineNumber(range.startOffset)?.plus(1)
+            }
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JvmDependenciesIndexImpl.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt
similarity index 94%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JvmDependenciesIndexImpl.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt
index 1075665ed4a..42fda615134 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/JvmDependenciesIndexImpl.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt
@@ -14,22 +14,23 @@
  * limitations under the License.
  */
 
-package org.jetbrains.kotlin.cli.jvm.index
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.ide.highlighter.JavaClassFileType
 import com.intellij.ide.highlighter.JavaFileType
 import com.intellij.openapi.vfs.VfsUtilCore
 import com.intellij.openapi.vfs.VirtualFile
-import it.unimi.dsi.fastutil.ints.IntArrayList
 import gnu.trove.THashMap
+import it.unimi.dsi.fastutil.ints.IntArrayList
+import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
+import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
 import org.jetbrains.kotlin.name.ClassId
 import org.jetbrains.kotlin.name.FqName
-import java.util.*
 
 // speeds up finding files/classes in classpath/java source roots
 // NOT THREADSAFE, needs to be adapted/removed if we want compiler to be multithreaded
 // the main idea of this class is for each package to store roots which contains it to avoid excessive file system traversal
-class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
+internal class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
     //these fields are computed based on _roots passed to constructor which are filled in later
     private val roots: List by lazy { _roots.toList() }
 
@@ -54,7 +55,7 @@ class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
         Cache().apply {
             roots.indices.forEach(rootIndices::add)
             rootIndices.add(maxIndex)
-            rootIndices.trim()
+            rootIndices.trimToSize(0)
         }
     }
 
@@ -139,7 +140,7 @@ class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
                 }
             }
             processedRootsUpTo =
-                if (cacheRootIndices.isEmpty) {
+                if (cacheRootIndices.isEmpty()) {
                     processedRootsUpTo
                 } else {
                     cacheRootIndices.getInt(cacheRootIndices.size - 1)
@@ -165,7 +166,7 @@ class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
             for (i in (fillCachesAfter + 1) until cachesPath.size) {
                 // we all know roots that contain this package by now
                 cachesPath[i].rootIndices.add(maxIndex)
-                cachesPath[i].rootIndices.trim()
+                cachesPath[i].rootIndices.trimToSize(0)
             }
             return null
         }
@@ -235,7 +236,12 @@ class JvmDependenciesIndexImpl(_roots: List) : JvmDependenciesIndex {
         return caches
     }
 
-    private data class FindClassRequest(val classId: ClassId, override val acceptedRootTypes: Set) : SearchRequest {
+    private fun  MutableList.trimToSize(newSize: Int) {
+        subList(newSize, size).clear()
+    }
+
+    private data class FindClassRequest(val classId: ClassId, override val acceptedRootTypes: Set) :
+        SearchRequest {
         override val packageFqName: FqName
             get() = classId.packageFqName
     }
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt
similarity index 69%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt
index 27328a6ce67..b4a1b8f7392 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinAnalysis.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt
@@ -1,21 +1,21 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
 import org.jetbrains.dokka.DokkaSourceSetID
+import org.jetbrains.dokka.InternalDokkaApi
 import org.jetbrains.dokka.model.SourceSetDependent
 import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.utilities.DokkaLogger
 import java.io.Closeable
 
 @Suppress("FunctionName")
-fun ProjectKotlinAnalysis(
+internal fun ProjectKotlinAnalysis(
     sourceSets: List,
-    logger: DokkaLogger,
+    context: DokkaContext,
     analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()
 ): KotlinAnalysis {
     val environments = sourceSets.associateWith { sourceSet ->
         createAnalysisContext(
-            logger = logger,
+            context = context,
             sourceSets = sourceSets,
             sourceSet = sourceSet,
             analysisConfiguration = analysisConfiguration
@@ -30,9 +30,9 @@ fun ProjectKotlinAnalysis(
  *  it's been used, there's no need to wait for [projectKotlinAnalysis] to be closed as it must be handled separately.
  */
 @Suppress("FunctionName")
-fun SamplesKotlinAnalysis(
+internal fun SamplesKotlinAnalysis(
     sourceSets: List,
-    logger: DokkaLogger,
+    context: DokkaContext,
     projectKotlinAnalysis: KotlinAnalysis,
     analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()
 ): KotlinAnalysis {
@@ -40,7 +40,7 @@ fun SamplesKotlinAnalysis(
         .filter { it.samples.isNotEmpty() }
         .associateWith { sourceSet ->
             createAnalysisContext(
-                logger = logger,
+                context = context,
                 classpath = sourceSet.classpath,
                 sourceRoots = sourceSet.samples,
                 sourceSet = sourceSet,
@@ -51,7 +51,7 @@ fun SamplesKotlinAnalysis(
     return EnvironmentKotlinAnalysis(environments, projectKotlinAnalysis)
 }
 
-class DokkaAnalysisConfiguration(
+internal class DokkaAnalysisConfiguration(
     /**
      * Only for common platform ignore BuiltIns for StdLib since it can cause a conflict
      * between BuiltIns from a compiler and ones from source code.
@@ -59,42 +59,25 @@ class DokkaAnalysisConfiguration(
     val ignoreCommonBuiltIns: Boolean = false
 )
 
-@Deprecated(
-    message = "Construct using list of DokkaSourceSets and logger",
-    replaceWith = ReplaceWith("KotlinAnalysis(context.configuration.sourceSets, context.logger)")
-)
-fun KotlinAnalysis(context: DokkaContext): KotlinAnalysis =
-    ProjectKotlinAnalysis(context.configuration.sourceSets, context.logger)
-
-@Deprecated(
-    message = "It was renamed to `ProjectKotlinAnalysis`",
-    replaceWith = ReplaceWith("ProjectKotlinAnalysis(sourceSets, logger, analysisConfiguration)")
-)
-fun KotlinAnalysis(
-    sourceSets: List,
-    logger: DokkaLogger,
-    analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration()
-) = ProjectKotlinAnalysis(sourceSets, logger, analysisConfiguration)
-
-
 /**
  * First child delegation. It does not close [parent].
  */
+@InternalDokkaApi
 abstract class KotlinAnalysis(
-    val parent: KotlinAnalysis? = null
+    private val parent: KotlinAnalysis? = null
 ) : Closeable {
 
     operator fun get(key: DokkaSourceSet): AnalysisContext {
         return get(key.sourceSetID)
     }
 
-    operator fun get(key: DokkaSourceSetID): AnalysisContext {
+    internal operator fun get(key: DokkaSourceSetID): AnalysisContext {
         return find(key)
             ?: parent?.get(key)
             ?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSet $key")
     }
 
-    protected abstract fun find(sourceSetID: DokkaSourceSetID): AnalysisContext?
+    internal abstract fun find(sourceSetID: DokkaSourceSetID): AnalysisContext?
 }
 
 internal open class EnvironmentKotlinAnalysis(
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinCliJavaFileManagerImpl.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt
similarity index 96%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinCliJavaFileManagerImpl.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt
index 37a5e3f775e..ac120b62fed 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/KotlinCliJavaFileManagerImpl.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.jetbrains.kotlin.cli.jvm.compiler
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.core.CoreJavaFileManager
 import com.intellij.openapi.diagnostic.Logger
@@ -25,6 +25,7 @@ import com.intellij.psi.impl.file.PsiPackageImpl
 import com.intellij.psi.search.GlobalSearchScope
 import gnu.trove.THashMap
 import gnu.trove.THashSet
+import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
 import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
 import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
 import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
@@ -39,13 +40,11 @@ import org.jetbrains.kotlin.name.ClassId
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
 import org.jetbrains.kotlin.util.PerformanceCounter
-import org.jetbrains.kotlin.utils.addIfNotNull
-import java.util.*
 
 // TODO: do not inherit from CoreJavaFileManager to avoid accidental usage of its methods which do not use caches/indices
 // Currently, the only relevant usage of this class as CoreJavaFileManager is at CoreJavaDirectoryService.getPackage,
 // which is indirectly invoked from PsiPackage.getSubPackages
-class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
+internal class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
     private val perfCounter = PerformanceCounter.create("Find Java class")
     private lateinit var index: JvmDependenciesIndex
     private lateinit var singleJavaFileRootsIndex: SingleJavaFileRootsIndex
@@ -175,11 +174,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
                 true
             }
 
-            result.addIfNotNull(
-                singleJavaFileRootsIndex.findJavaSourceClass(classId)
-                    ?.takeIf { it in scope }
-                    ?.findPsiClassInVirtualFile(relativeClassName)
-            )
+            singleJavaFileRootsIndex.findJavaSourceClass(classId)
+                ?.takeIf { it in scope }
+                ?.findPsiClassInVirtualFile(relativeClassName)
+                ?.let { result.add(it) }
 
             if (result.isNotEmpty()) {
                 return@time result.toTypedArray()
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt
similarity index 88%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt
index 091e54ce585..f271e1f1732 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration
 
 import com.intellij.psi.PsiClass
 import org.jetbrains.dokka.links.*
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.types.error.ErrorType
 import org.jetbrains.kotlin.types.error.ErrorTypeConstructor
 import org.jetbrains.kotlin.types.error.ErrorTypeKind
 
-fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference? =
+internal fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference? =
     when (d.value) {
         is ExtensionReceiver -> fromPossiblyNullable(d.type, emptyList())
         else -> run {
@@ -22,10 +22,10 @@ fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference?
         }
     }
 
-fun TypeReference.Companion.from(d: ValueParameterDescriptor): TypeReference =
+internal fun TypeReference.Companion.from(d: ValueParameterDescriptor): TypeReference =
     fromPossiblyNullable(d.type, emptyList())
 
-fun TypeReference.Companion.from(@Suppress("UNUSED_PARAMETER") p: PsiClass) = TypeReference
+internal fun TypeReference.Companion.from(@Suppress("UNUSED_PARAMETER") p: PsiClass) = TypeReference
 
 private fun TypeReference.Companion.fromPossiblyNullable(t: KotlinType, paramTrace: List): TypeReference =
     fromPossiblyRecursive(t, paramTrace).let { if (t.isMarkedNullable) Nullable(it) else it }
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/CommonKlibModuleInfo.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt
similarity index 91%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/CommonKlibModuleInfo.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt
index 22c86dd7743..a7667009261 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/CommonKlibModuleInfo.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.analyzer.ModuleInfo
 import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
@@ -22,4 +22,4 @@ internal class CommonKlibModuleInfo(
 
     override val analyzerServices: PlatformDependentAnalyzerServices
         get() = CommonPlatformAnalyzerServices
-}
\ No newline at end of file
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsKlibLibraryInfo.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt
similarity index 93%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsKlibLibraryInfo.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt
index 9d28cc3c7f6..675bf28ea77 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsKlibLibraryInfo.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.analyzer.ModuleInfo
 import org.jetbrains.kotlin.library.KotlinLibrary
@@ -27,4 +27,4 @@ internal class DokkaJsKlibLibraryInfo(
     override val platform: TargetPlatform = JsPlatforms.defaultJsPlatform
     override fun dependencies(): List = listOf(this) + dependencyResolver.resolveDependencies(this)
     override fun getLibraryRoots(): Collection = listOf(libraryRoot)
-}
\ No newline at end of file
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsResolverForModuleFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt
similarity index 85%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsResolverForModuleFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt
index 353c71fba36..b409441b2f9 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaJsResolverForModuleFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt
@@ -1,5 +1,6 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KLibService
 import org.jetbrains.kotlin.analyzer.*
 import org.jetbrains.kotlin.builtins.DefaultBuiltIns
 import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -10,7 +11,6 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
 import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
 import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
 import org.jetbrains.kotlin.frontend.di.createContainerForLazyResolve
-import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
 import org.jetbrains.kotlin.incremental.components.LookupTracker
 import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
 import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
@@ -28,7 +28,8 @@ import java.io.File
 
 /** TODO: replace by [org.jetbrains.kotlin.caches.resolve.JsResolverForModuleFactory] after fix of KT-40734 */
 internal class DokkaJsResolverForModuleFactory(
-    private val targetEnvironment: TargetEnvironment
+    private val targetEnvironment: TargetEnvironment,
+    private val kLibService: KLibService
 ) : ResolverForModuleFactory() {
     companion object {
         private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, DynamicTypeDeserializer)
@@ -86,16 +87,18 @@ internal class DokkaJsResolverForModuleFactory(
         languageVersionSettings: LanguageVersionSettings
     ): List = when (moduleInfo) {
         is DokkaJsKlibLibraryInfo -> {
-            listOfNotNull(
-                moduleInfo.kotlinLibrary
-                    .createKlibPackageFragmentProvider(
-                        storageManager = moduleContext.storageManager,
-                        metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
-                        languageVersionSettings = languageVersionSettings,
-                        moduleDescriptor = moduleDescriptor,
-                        lookupTracker = LookupTracker.DO_NOTHING
-                    )
-            )
+            with(kLibService) {
+                listOfNotNull(
+                    moduleInfo.kotlinLibrary
+                        .createPackageFragmentProvider(
+                            storageManager = moduleContext.storageManager,
+                            metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
+                            languageVersionSettings = languageVersionSettings,
+                            moduleDescriptor = moduleDescriptor,
+                            lookupTracker = LookupTracker.DO_NOTHING
+                        )
+                )
+            }
         }
         is LibraryModuleInfo -> {
             moduleInfo.getLibraryRoots()
@@ -119,4 +122,4 @@ internal class DokkaJsResolverForModuleFactory(
         }
         else -> emptyList()
     }
-}
\ No newline at end of file
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryDependencyResolver.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt
similarity index 88%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryDependencyResolver.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt
index 9259deff7e7..a07bdc35bee 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryDependencyResolver.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.library.uniqueName
 import org.jetbrains.kotlin.library.unresolvedDependencies
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryInfo.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt
similarity index 60%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryInfo.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt
index e4e12b660df..3362633d47a 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibLibraryInfo.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt
@@ -1,10 +1,10 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.analyzer.LibraryModuleInfo
 import org.jetbrains.kotlin.library.KotlinLibrary
 
-abstract class DokkaKlibLibraryInfo : LibraryModuleInfo {
+internal abstract class DokkaKlibLibraryInfo : LibraryModuleInfo {
     abstract val kotlinLibrary: KotlinLibrary
     internal val libraryRoot: String
         get() = kotlinLibrary.libraryFile.path
-}
\ No newline at end of file
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibMetadataCommonDependencyContainer.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt
similarity index 96%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibMetadataCommonDependencyContainer.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt
index 1a987a1f7c0..95f5486df74 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaKlibMetadataCommonDependencyContainer.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.analyzer.ModuleInfo
 import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
@@ -20,12 +20,11 @@ import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
 import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
 import org.jetbrains.kotlin.storage.LockBasedStorageManager
 import org.jetbrains.kotlin.storage.StorageManager
-import org.jetbrains.kotlin.utils.keysToMap
 
 /**
  * Adapted from org.jetbrains.kotlin.cli.metadata.KlibMetadataDependencyContainer
  */
-class DokkaKlibMetadataCommonDependencyContainer(
+internal class DokkaKlibMetadataCommonDependencyContainer(
     kotlinLibraries: List,
     private val configuration: CompilerConfiguration,
     private val storageManager: StorageManager
@@ -41,7 +40,7 @@ class DokkaKlibMetadataCommonDependencyContainer(
     private val mutableDependenciesForAllModules = mutableListOf()
 
     private val moduleDescriptorsForKotlinLibraries: Map =
-        kotlinLibraries.keysToMap { library ->
+        kotlinLibraries.associateBy({ it }) { library ->
             val moduleHeader = parseModuleHeader(library.moduleHeaderData)
             val moduleName = Name.special(moduleHeader.moduleName)
             val moduleOrigin = DeserializedKlibModuleOrigin(library)
@@ -137,4 +136,4 @@ private val MetadataFactories =
         { DefaultBuiltIns.Instance },
         NullFlexibleTypeDeserializer,
         NativeTypeTransformer()
-    )
\ No newline at end of file
+    )
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeKlibLibraryInfo.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt
similarity index 87%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeKlibLibraryInfo.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt
index e2b388a94f5..526815d3e71 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeKlibLibraryInfo.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt
@@ -1,10 +1,9 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
 import org.jetbrains.kotlin.analyzer.ModuleInfo
 import org.jetbrains.kotlin.descriptors.ModuleCapability
 import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
 import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
-import org.jetbrains.kotlin.idea.klib.safeRead
 import org.jetbrains.kotlin.library.KotlinLibrary
 import org.jetbrains.kotlin.library.isInterop
 import org.jetbrains.kotlin.library.shortName
@@ -14,6 +13,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
 import org.jetbrains.kotlin.platform.konan.NativePlatforms
 import org.jetbrains.kotlin.resolve.ImplicitIntegerCoercion
 import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
+import java.io.IOException
 
 /** TODO: replace by [NativeKlibLibraryInfo] after fix of KT-40734 */
 internal class DokkaNativeKlibLibraryInfo(
@@ -41,4 +41,10 @@ internal class DokkaNativeKlibLibraryInfo(
             capabilities[ImplicitIntegerCoercion.MODULE_CAPABILITY] = kotlinLibrary.safeRead(false) { isInterop }
             return capabilities
         }
+
+    private fun  KotlinLibrary.safeRead(defaultValue: T, action: KotlinLibrary.() -> T) = try {
+        action()
+    } catch (_: IOException) {
+        defaultValue
+    }
 }
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeResolverForModuleFactory.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt
similarity index 76%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeResolverForModuleFactory.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt
index 0114f1acac7..db86b82f496 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/resolve/DokkaNativeResolverForModuleFactory.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt
@@ -1,5 +1,6 @@
-package org.jetbrains.dokka.analysis.resolve
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve
 
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KLibService
 import org.jetbrains.kotlin.analyzer.*
 import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
 import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -8,7 +9,6 @@ import org.jetbrains.kotlin.context.ModuleContext
 import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
 import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
 import org.jetbrains.kotlin.frontend.di.createContainerForLazyResolve
-import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
 import org.jetbrains.kotlin.incremental.components.LookupTracker
 import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
 import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
@@ -21,7 +21,8 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
 
 /** TODO: replace by [NativeResolverForModuleFactory] after fix of KT-40734 */
 internal class DokkaNativeResolverForModuleFactory(
-    private val targetEnvironment: TargetEnvironment
+    private val targetEnvironment: TargetEnvironment,
+    private val kLibService: KLibService,
 ) : ResolverForModuleFactory() {
     companion object {
         private val metadataFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer)
@@ -56,15 +57,17 @@ internal class DokkaNativeResolverForModuleFactory(
 
         var packageFragmentProvider = container.get().packageFragmentProvider
 
-        val klibPackageFragmentProvider = (moduleContent.moduleInfo as? DokkaNativeKlibLibraryInfo)
-            ?.kotlinLibrary
-            ?.createKlibPackageFragmentProvider(
-                storageManager = moduleContext.storageManager,
-                metadataModuleDescriptorFactory = metadataFactories.DefaultDeserializedDescriptorFactory,
-                languageVersionSettings = languageVersionSettings,
-                moduleDescriptor = moduleDescriptor,
-                lookupTracker = LookupTracker.DO_NOTHING
-            )
+        val klibPackageFragmentProvider = with(kLibService) {
+            (moduleContent.moduleInfo as? DokkaNativeKlibLibraryInfo)
+                ?.kotlinLibrary
+                ?.createPackageFragmentProvider(
+                    storageManager = moduleContext.storageManager,
+                    metadataModuleDescriptorFactory = metadataFactories.DefaultDeserializedDescriptorFactory,
+                    languageVersionSettings = languageVersionSettings,
+                    moduleDescriptor = moduleDescriptor,
+                    lookupTracker = LookupTracker.DO_NOTHING
+                )
+        }
 
         if (klibPackageFragmentProvider != null) {
             packageFragmentProvider =
diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DefaultSamplesTransformer.kt
similarity index 81%
rename from plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DefaultSamplesTransformer.kt
index 49ddd0a564f..22fecdf83e3 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DefaultSamplesTransformer.kt
@@ -1,13 +1,12 @@
-package org.jetbrains.dokka.base.transformers.pages.samples
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
 
 import com.intellij.psi.PsiElement
 import org.jetbrains.dokka.plugability.DokkaContext
 import org.jetbrains.kotlin.psi.KtBlockExpression
 import org.jetbrains.kotlin.psi.KtDeclarationWithBody
 import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.utils.addToStdlib.safeAs
 
-class DefaultSamplesTransformer(context: DokkaContext) : SamplesTransformer(context) {
+internal class DefaultSamplesTransformer(context: DokkaContext) : SamplesTransformerImpl(context) {
 
     override fun processBody(psiElement: PsiElement): String {
         val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd()
@@ -28,9 +27,9 @@ class DefaultSamplesTransformer(context: DokkaContext) : SamplesTransformer(cont
 
     override fun processImports(psiElement: PsiElement): String {
         val psiFile = psiElement.containingFile
-        return when(val text = psiFile.safeAs()?.importList?.text) {
+        return when(val text = (psiFile as? KtFile)?.importList?.text) {
             is String -> text
             else -> ""
         }
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt
similarity index 78%
rename from plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt
index d657fa32882..33262761ae5 100644
--- a/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt
@@ -1,26 +1,27 @@
-package org.jetbrains.dokka.base.transformers.documentables.utils
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
 
 import com.intellij.psi.PsiClass
-import kotlinx.coroutines.*
-import org.jetbrains.dokka.analysis.DescriptorDocumentableSource
-import org.jetbrains.dokka.analysis.PsiDocumentableSource
-import org.jetbrains.dokka.analysis.from
+import kotlinx.coroutines.coroutineScope
+import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.DescriptorDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.*
 import org.jetbrains.dokka.utilities.parallelForEach
+import org.jetbrains.kotlin.analysis.kotlin.ClassHierarchy
+import org.jetbrains.kotlin.analysis.kotlin.FullClassHierarchyBuilder
+import org.jetbrains.kotlin.analysis.kotlin.Supertypes
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.types.KotlinType
 import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
 import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
 import java.util.concurrent.ConcurrentHashMap
 
-typealias Supertypes = List
-typealias ClassHierarchy = SourceSetDependent>
+internal class DescriptorFullClassHierarchyBuilder : FullClassHierarchyBuilder {
 
-class FullClassHierarchyBuilder {
-    suspend operator fun invoke(original: DModule): ClassHierarchy = coroutineScope {
-        val map = original.sourceSets.associateWith { ConcurrentHashMap>() }
-        original.packages.parallelForEach { visitDocumentable(it, map) }
+    override suspend fun build(module: DModule): ClassHierarchy = coroutineScope {
+        val map = module.sourceSets.associateWith { ConcurrentHashMap>() }
+        module.packages.parallelForEach { visitDocumentable(it, map) }
         map
     }
 
@@ -81,4 +82,4 @@ class FullClassHierarchyBuilder {
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt
new file mode 100644
index 00000000000..ef8785a77bd
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt
@@ -0,0 +1,91 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
+
+import com.intellij.psi.PsiClass
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.DescriptorDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.WithSources
+import org.jetbrains.kotlin.analysis.kotlin.InheritanceBuilder
+import org.jetbrains.kotlin.analysis.kotlin.InheritanceNode
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType
+
+internal class DescriptorInheritanceBuilder : InheritanceBuilder {
+
+    override fun build(documentables: Map): List {
+        val descriptorMap = getDescriptorMap(documentables)
+
+        val psiInheritanceTree =
+            documentables.flatMap { (_, v) -> (v as? WithSources)?.sources?.values.orEmpty() }
+                .filterIsInstance().mapNotNull { it.psi as? PsiClass }
+                .flatMap(::gatherPsiClasses)
+                .flatMap { entry -> entry.second.map { it to entry.first } }
+                .let {
+                    it + it.map { it.second to null }
+                }
+                .groupBy({ it.first }) { it.second }
+                .map { it.key to it.value.filterNotNull().distinct() }
+                .map { (k, v) ->
+                    InheritanceNode(
+                        DRI.from(k),
+                        v.map { InheritanceNode(DRI.from(it)) },
+                        k.supers.filter { it.isInterface }.map { DRI.from(it) },
+                        k.isInterface
+                    )
+
+                }
+
+        val descriptorInheritanceTree = descriptorMap.flatMap { (_, v) ->
+            v.typeConstructor.supertypes
+                .map { getClassDescriptorForType(it) to v }
+        }
+            .let {
+                it + it.map { it.second to null }
+            }
+            .groupBy({ it.first }) { it.second }
+            .map { it.key to it.value.filterNotNull().distinct() }
+            .map { (k, v) ->
+                InheritanceNode(
+                    DRI.from(k),
+                    v.map { InheritanceNode(DRI.from(it)) },
+                    k.typeConstructor.supertypes.map { getClassDescriptorForType(it) }
+                        .mapNotNull { cd -> cd.takeIf { it.kind == ClassKind.INTERFACE }?.let { DRI.from(it) } },
+                    isInterface = k.kind == ClassKind.INTERFACE
+                )
+            }
+
+        return psiInheritanceTree + descriptorInheritanceTree
+    }
+
+    private fun gatherPsiClasses(psi: PsiClass): List>> = psi.supers.toList().let { l ->
+        listOf(psi to l) + l.flatMap { gatherPsiClasses(it) }
+    }
+
+    private fun getDescriptorMap(documentables: Map): Map {
+        val map: MutableMap = mutableMapOf()
+        documentables
+            .mapNotNull { (k, v) ->
+                v.descriptorForPlatform()?.let { k to it }?.also { (k, v) -> map[k] = v }
+            }.map { it.second }.forEach { gatherSupertypes(it, map) }
+
+        return map.toMap()
+    }
+
+    private fun gatherSupertypes(descriptor: ClassDescriptor, map: MutableMap) {
+        map.putIfAbsent(DRI.from(descriptor), descriptor)
+        descriptor.typeConstructor.supertypes.map { getClassDescriptorForType(it) }
+            .forEach { gatherSupertypes(it, map) }
+    }
+
+
+    private fun Documentable?.descriptorForPlatform(platform: Platform = Platform.jvm) =
+        (this as? WithSources).descriptorForPlatform(platform)
+
+    private fun WithSources?.descriptorForPlatform(platform: Platform = Platform.jvm) = this?.let {
+        it.sources.entries.find { it.key.analysisPlatform == platform }?.value?.let { it as? DescriptorDocumentableSource }?.descriptor as? ClassDescriptor
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt
new file mode 100644
index 00000000000..bbf27d24179
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt
@@ -0,0 +1,31 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
+
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.PointingToDeclaration
+import org.jetbrains.kotlin.analysis.kotlin.KotlinToJavaMapper
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+
+internal class DescriptorKotlinToJavaMapper : KotlinToJavaMapper {
+
+    override fun findAsJava(kotlinDri: DRI): DRI? {
+        return kotlinDri.partialFqName().mapToJava()?.toDRI(kotlinDri)
+    }
+
+    private fun DRI.partialFqName() = packageName?.let { "$it." } + classNames
+
+    private fun String.mapToJava(): ClassId? =
+        JavaToKotlinClassMap.mapKotlinToJava(FqName(this).toUnsafe())
+
+    private fun ClassId.toDRI(dri: DRI?): DRI = DRI(
+        packageName = packageFqName.asString(),
+        classNames = classNames(),
+        callable = dri?.callable,//?.asJava(), TODO: check this
+        extra = null,
+        target = PointingToDeclaration
+    )
+
+    private fun ClassId.classNames(): String =
+        shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "")
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt
new file mode 100644
index 00000000000..fce72015f25
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt
@@ -0,0 +1,33 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.DescriptorDocumentableSource
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.WithSources
+import org.jetbrains.kotlin.analysis.kotlin.SyntheticDocumentableDetector
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+
+internal class DescriptorSyntheticDocumentableDetector : SyntheticDocumentableDetector {
+    override fun isSynthetic(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean {
+        return isFakeOverride(documentable, sourceSet) || isSynthesized(documentable, sourceSet)
+    }
+
+    private fun isFakeOverride(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean {
+        return callableMemberDescriptorOrNull(documentable, sourceSet)?.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
+    }
+
+    private fun isSynthesized(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean {
+        return callableMemberDescriptorOrNull(documentable, sourceSet)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
+    }
+
+    private fun callableMemberDescriptorOrNull(
+        documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet
+    ): CallableMemberDescriptor? {
+        if (documentable is WithSources) {
+            return documentable.sources[sourceSet]
+                .let { it as? DescriptorDocumentableSource }?.descriptor as? CallableMemberDescriptor
+        }
+
+        return null
+    }
+}
diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/SamplesTransformerImpl.kt
similarity index 74%
rename from plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/SamplesTransformerImpl.kt
index e72700e08c8..f1924708e2d 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/SamplesTransformerImpl.kt
@@ -1,12 +1,13 @@
-package org.jetbrains.dokka.base.transformers.pages.samples
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl
 
 import com.intellij.psi.PsiElement
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
-import org.jetbrains.dokka.analysis.*
-import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.base.renderers.sourceSets
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.KotlinAnalysis
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.SamplesKotlinAnalysis
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.DisplaySourceSet
 import org.jetbrains.dokka.model.doc.Sample
@@ -16,13 +17,15 @@ import org.jetbrains.dokka.plugability.DokkaContext
 import org.jetbrains.dokka.plugability.plugin
 import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.transformers.pages.PageTransformer
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
 import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.BindingContext
 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
 
-internal const val KOTLIN_PLAYGROUND_SCRIPT = ""
-abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
+internal const val KOTLIN_PLAYGROUND_SCRIPT = ""
+
+internal abstract class SamplesTransformerImpl(val context: DokkaContext) : PageTransformer {
+
+    private val kDocFinder: KDocFinder = context.plugin().querySingle { kdocFinder }
 
     abstract fun processBody(psiElement: PsiElement): String
     abstract fun processImports(psiElement: PsiElement): String
@@ -36,8 +39,8 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
         runBlocking(Dispatchers.Default) {
             val analysis = SamplesKotlinAnalysis(
                 sourceSets = context.configuration.sourceSets,
-                logger = context.logger,
-                projectKotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+                context = context,
+                projectKotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
             )
             analysis.use {
                 input.transformContentPagesTree { page ->
@@ -63,13 +66,13 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
         fqName: String,
         analysis: KotlinAnalysis
     ): ContentNode {
-        val facade = analysis[sourceSet].facade
-        val psiElement = fqNameToPsiElement(facade, fqName)
+        val resolveSession = analysis[sourceSet].resolveSession
+        val psiElement = fqNameToPsiElement(resolveSession, fqName, sourceSet)
             ?: return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") }
         val imports =
             processImports(psiElement)
         val body = processBody(psiElement)
-        val node = contentCode(contentPage.sourceSets(), contentPage.dri, createSampleBody(imports, body), "kotlin")
+        val node = contentCode(contentPage.content.sourceSets, contentPage.dri, createSampleBody(imports, body), "kotlin")
 
         return dfs(fqName, node)
     }
@@ -107,18 +110,20 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
         }
     }
 
-    private fun fqNameToPsiElement(resolutionFacade: DokkaResolutionFacade, functionName: String): PsiElement? {
+    private fun fqNameToPsiElement(resolveSession: ResolveSession, functionName: String, dokkaSourceSet: DokkaSourceSet): PsiElement? {
         val packageName = functionName.takeWhile { it != '.' }
-        val descriptor = resolutionFacade.resolveSession.getPackageFragment(FqName(packageName))
+        val descriptor = resolveSession.getPackageFragment(FqName(packageName))
             ?: return null.also { context.logger.warn("Cannot find descriptor for package $packageName") }
-        val symbol = resolveKDocLink(
-            BindingContext.EMPTY,
-            resolutionFacade,
-            descriptor,
-            null,
-            functionName.split(".")
-        ).firstOrNull() ?: return null.also { context.logger.warn("Unresolved function $functionName in @sample") }
-        return DescriptorToSourceUtils.descriptorToDeclaration(symbol)
+
+        with (kDocFinder) {
+            val symbol = resolveKDocLink(
+                descriptor,
+                functionName,
+                dokkaSourceSet,
+                emptyBindingContext = true
+            ).firstOrNull() ?: return null.also { context.logger.warn("Unresolved function $functionName in @sample") }
+            return DescriptorToSourceUtils.descriptorToDeclaration(symbol)
+        }
     }
 
     private fun contentCode(
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt
similarity index 71%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt
index f642c3745be..0d5fe5c547f 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
 import org.jetbrains.dokka.DokkaException
 
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt
similarity index 60%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt
index ee67fad1ca6..0aaea9c8d6f 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt
@@ -1,8 +1,8 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
 import org.jetbrains.dokka.model.doc.DocumentationNode
 
-data class ModuleAndPackageDocumentation(
+internal data class ModuleAndPackageDocumentation(
     val name: String,
     val classifier: Classifier,
     val documentation: DocumentationNode
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt
new file mode 100644
index 00000000000..c0df713be06
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt
@@ -0,0 +1,9 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
+
+
+internal data class ModuleAndPackageDocumentationFragment(
+    val name: String,
+    val classifier: ModuleAndPackageDocumentation.Classifier,
+    val documentation: String,
+    val source: ModuleAndPackageDocumentationSource
+)
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt
similarity index 50%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt
index fa6c653ef36..c443b5b5ce6 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt
@@ -1,21 +1,22 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
-import org.jetbrains.dokka.analysis.DokkaResolutionFacade
-import org.jetbrains.dokka.analysis.from
-import org.jetbrains.dokka.base.parsers.MarkdownParser
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Package
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier.Module
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier.Package
+import org.jetbrains.dokka.analysis.markdown.MarkdownParser
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.doc.DocumentationNode
 import org.jetbrains.dokka.utilities.DokkaLogger
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.name.Name
 
-fun interface ModuleAndPackageDocumentationParsingContext {
+internal fun interface ModuleAndPackageDocumentationParsingContext {
     fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment, location: String): MarkdownParser
 }
 
@@ -25,25 +26,31 @@ internal fun ModuleAndPackageDocumentationParsingContext.parse(
     return markdownParserFor(fragment, fragment.source.sourceDescription).parse(fragment.documentation)
 }
 
-fun ModuleAndPackageDocumentationParsingContext(
+internal fun ModuleAndPackageDocumentationParsingContext(
     logger: DokkaLogger,
-    facade: DokkaResolutionFacade? = null
+    moduleDescriptor: ModuleDescriptor? = null,
+    kDocFinder: KDocFinder? = null,
+    sourceSet: DokkaConfiguration.DokkaSourceSet? = null
 ) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation ->
     val descriptor = when (fragment.classifier) {
-        Module -> facade?.moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier("")))
-        Package -> facade?.moduleDescriptor?.getPackage(FqName(fragment.name))
+        Module -> moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier("")))
+        Package -> moduleDescriptor?.getPackage(FqName(fragment.name))
     }
 
     val externalDri = { link: String ->
         try {
-            if (facade != null && descriptor != null) {
-                resolveKDocLink(
-                    facade.resolveSession.bindingContext,
-                    facade,
-                    descriptor,
-                    null,
-                    link.split('.')
-                ).sorted().firstOrNull()?.let { DRI.from(it) }
+            if (kDocFinder != null && descriptor != null && sourceSet != null) {
+                with(kDocFinder) {
+                    resolveKDocLink(
+                        descriptor,
+                        link,
+                        sourceSet
+                    ).sorted().firstOrNull()?.let {
+                        DRI.from(
+                            it
+                        )
+                    }
+                }
             } else null
         } catch (e1: IllegalArgumentException) {
             logger.warn("Couldn't resolve link for $link")
diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt
similarity index 70%
rename from plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt
index faf94db2317..05dad18c9f6 100644
--- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt
@@ -1,13 +1,10 @@
-package org.jetbrains.dokka.base.transformers.documentables
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
 import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.analysis.KotlinAnalysis
-import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationFragment
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.KotlinAnalysis
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier
 import org.jetbrains.dokka.model.DModule
 import org.jetbrains.dokka.model.DPackage
 import org.jetbrains.dokka.model.SourceSetDependent
@@ -17,11 +14,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
 import org.jetbrains.dokka.plugability.plugin
 import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.utilities.associateWithNotNull
-
-internal interface ModuleAndPackageDocumentationReader {
-    operator fun get(module: DModule): SourceSetDependent
-    operator fun get(pkg: DPackage): SourceSetDependent
-}
+import org.jetbrains.kotlin.analysis.kotlin.ModuleAndPackageDocumentationReader
 
 internal fun ModuleAndPackageDocumentationReader(context: DokkaContext): ModuleAndPackageDocumentationReader =
     ContextModuleAndPackageDocumentationReader(context)
@@ -30,7 +23,8 @@ private class ContextModuleAndPackageDocumentationReader(
     private val context: DokkaContext
 ) : ModuleAndPackageDocumentationReader {
 
-    private val kotlinAnalysis: KotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+    private val kotlinAnalysis: KotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+    private val kdocFinder: KDocFinder = context.plugin().querySingle { kdocFinder }
 
     private val documentationFragments: SourceSetDependent> =
         context.configuration.sourceSets.associateWith { sourceSet ->
@@ -43,10 +37,10 @@ private class ContextModuleAndPackageDocumentationReader(
     ): SourceSetDependent {
         return sourceSets.associateWithNotNull { sourceSet ->
             val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate)
-            val resolutionFacade = kotlinAnalysis[sourceSet].facade
+            val moduleDescriptor = kotlinAnalysis[sourceSet].moduleDescriptor
             val documentations = fragments.map { fragment ->
                 parseModuleAndPackageDocumentation(
-                    context = ModuleAndPackageDocumentationParsingContext(context.logger, resolutionFacade),
+                    context = ModuleAndPackageDocumentationParsingContext(context.logger, moduleDescriptor, kdocFinder, sourceSet),
                     fragment = fragment
                 )
             }
@@ -66,18 +60,30 @@ private class ContextModuleAndPackageDocumentationReader(
             return name
         }
 
-    override fun get(module: DModule): SourceSetDependent {
+    override fun read(module: DModule): SourceSetDependent {
         return findDocumentationNodes(module.sourceSets) { fragment ->
             fragment.classifier == Classifier.Module && (fragment.name == module.name)
         }
     }
 
-    override fun get(pkg: DPackage): SourceSetDependent {
+    override fun read(pkg: DPackage): SourceSetDependent {
         return findDocumentationNodes(pkg.sourceSets) { fragment ->
             fragment.classifier == Classifier.Package && fragment.canonicalPackageName == pkg.dri.packageName
         }
     }
 
+    override fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode? {
+        val parsingContext = ModuleAndPackageDocumentationParsingContext(context.logger)
+
+        val documentationFragment = module.includes
+            .flatMap { include -> parseModuleAndPackageDocumentationFragments(include) }
+            .firstOrNull { fragment -> fragment.classifier == Classifier.Module && fragment.name == module.name }
+            ?: return null
+
+        val moduleDocumentation = parseModuleAndPackageDocumentation(parsingContext, documentationFragment)
+        return moduleDocumentation.documentation
+    }
+
     private fun List.mergeDocumentationNodes(): List =
         groupBy { it::class }.values.map {
             it.reduce { acc, tagWrapper ->
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt
similarity index 75%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt
index 9514adb4afa..18105be04e2 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt
@@ -1,8 +1,8 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
 import java.io.File
 
-abstract class ModuleAndPackageDocumentationSource {
+internal abstract class ModuleAndPackageDocumentationSource {
     abstract val sourceDescription: String
     abstract val documentation: String
     override fun toString(): String = sourceDescription
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt
similarity index 70%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt
index db3420429a1..59b7d2e9ff1 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt
@@ -1,6 +1,6 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
-fun parseModuleAndPackageDocumentation(
+internal fun parseModuleAndPackageDocumentation(
     context: ModuleAndPackageDocumentationParsingContext,
     fragment: ModuleAndPackageDocumentationFragment
 ): ModuleAndPackageDocumentation {
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt
similarity index 78%
rename from plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt
index d3381901d85..32f636ff6b7 100644
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt
@@ -1,14 +1,14 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs
 
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier.Module
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier.Package
 import java.io.File
 
-
-fun parseModuleAndPackageDocumentationFragments(source: File): List {
+internal fun parseModuleAndPackageDocumentationFragments(source: File): List {
     return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source))
 }
 
-fun parseModuleAndPackageDocumentationFragments(
+internal fun parseModuleAndPackageDocumentationFragments(
     source: ModuleAndPackageDocumentationSource
 ): List {
     val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))"))
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt
new file mode 100644
index 00000000000..e11e3118ec5
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt
@@ -0,0 +1,16 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import org.jetbrains.dokka.analysis.java.DocumentationContent
+import org.jetbrains.dokka.analysis.java.JavadocTag
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+
+internal data class DescriptorDocumentationContent(
+    val descriptor: DeclarationDescriptor,
+    val element: KDocTag,
+    override val tag: JavadocTag,
+) : DocumentationContent {
+    override fun resolveSiblings(): List {
+        return listOf(this)
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt
new file mode 100644
index 00000000000..72151a72f2a
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt
@@ -0,0 +1,16 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import com.intellij.openapi.project.Project
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.java.ProjectProvider
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+
+internal class KotlinAnalysisProjectProvider : ProjectProvider {
+    override fun getProject(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): Project {
+        val kotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+        return kotlinAnalysis[sourceSet].project
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt
new file mode 100644
index 00000000000..8673774d4c0
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt
@@ -0,0 +1,26 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.java.SourceRootsExtractor
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
+import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
+import java.io.File
+
+internal class KotlinAnalysisSourceRootsExtractor : SourceRootsExtractor {
+    override fun extract(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): List {
+        val kotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+        val environment = kotlinAnalysis[sourceSet].environment
+        return environment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS)
+            ?.filterIsInstance()
+            ?.mapNotNull { it.file.takeIf { isFileInSourceRoots(it, sourceSet) } }
+            ?: listOf()
+    }
+
+    private fun isFileInSourceRoots(file: File, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean =
+        sourceSet.sourceRoots.any { root -> file.startsWith(root) }
+
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocComment.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocComment.kt
new file mode 100644
index 00000000000..9af9dfff59d
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocComment.kt
@@ -0,0 +1,77 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import org.jetbrains.dokka.analysis.java.*
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+
+internal class KotlinDocComment(
+    val comment: KDocTag,
+    val descriptor: DeclarationDescriptor
+) : DocComment {
+
+    private val tagsWithContent: List = comment.children.mapNotNull { (it as? KDocTag) }
+
+    override fun hasTag(tag: JavadocTag): Boolean {
+        return when (tag) {
+            is DescriptionJavadocTag -> comment.getContent().isNotEmpty()
+            is ThrowingExceptionJavadocTag -> tagsWithContent.any { it.hasException(tag) }
+            else -> tagsWithContent.any { it.text.startsWith("@${tag.name}") }
+        }
+    }
+
+    private fun KDocTag.hasException(tag: ThrowingExceptionJavadocTag) =
+        text.startsWith("@${tag.name}") && getSubjectName() == tag.exceptionQualifiedName
+
+    override fun resolveTag(tag: JavadocTag): List {
+        return when (tag) {
+            is DescriptionJavadocTag -> listOf(DescriptorDocumentationContent(descriptor, comment, tag))
+            is ParamJavadocTag -> {
+                val resolvedContent = resolveGeneric(tag)
+                listOf(resolvedContent[tag.paramIndex])
+            }
+
+            is ThrowsJavadocTag -> resolveThrowingException(tag)
+            is ExceptionJavadocTag -> resolveThrowingException(tag)
+            else -> resolveGeneric(tag)
+        }
+    }
+
+    private fun resolveThrowingException(tag: ThrowingExceptionJavadocTag): List {
+        val exceptionName = tag.exceptionQualifiedName ?: return resolveGeneric(tag)
+
+        return comment.children
+            .filterIsInstance()
+            .filter { it.name == tag.name && it.getSubjectName() == exceptionName }
+            .map { DescriptorDocumentationContent(descriptor, it, tag) }
+    }
+
+    private fun resolveGeneric(tag: JavadocTag): List {
+        return comment.children.mapNotNull { element ->
+            if (element is KDocTag && element.name == tag.name) {
+                DescriptorDocumentationContent(descriptor, element, tag)
+            } else {
+                null
+            }
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as KotlinDocComment
+
+        if (comment != other.comment) return false
+        if (descriptor != other.descriptor) return false
+        if (tagsWithContent != other.tagsWithContent) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = comment.hashCode()
+        result = 31 * result + descriptor.hashCode()
+        result = 31 * result + tagsWithContent.hashCode()
+        return result
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentCreator.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentCreator.kt
new file mode 100644
index 00000000000..68f2e9d2b01
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentCreator.kt
@@ -0,0 +1,26 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import com.intellij.psi.PsiNamedElement
+import org.jetbrains.dokka.analysis.java.DocComment
+import org.jetbrains.dokka.analysis.java.DocCommentCreator
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.SearchHelpers
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+
+internal class KotlinDocCommentCreator(
+    private val kdocFinder: KDocFinder,
+    private val searchHelpers: SearchHelpers
+) : DocCommentCreator {
+    override fun create(element: PsiNamedElement): DocComment? {
+        val ktElement = element.navigationElement as? KtElement ?: return null
+        val kdoc = with (kdocFinder) {
+            ktElement.findKDoc()
+        } ?: return null
+        val descriptor = with (searchHelpers) {
+            (element.navigationElement as? KtDeclaration)?.findDescriptor()
+        } ?: return null
+
+        return KotlinDocComment(kdoc, descriptor)
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentParser.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentParser.kt
new file mode 100644
index 00000000000..0360e8f6f22
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinDocCommentParser.kt
@@ -0,0 +1,54 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import com.intellij.psi.PsiNamedElement
+import org.jetbrains.dokka.Platform
+import org.jetbrains.dokka.analysis.java.DocComment
+import org.jetbrains.dokka.analysis.java.DocCommentParser
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator.parseFromKDocTag
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.doc.DocumentationNode
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+internal class KotlinDocCommentParser(
+    private val context: DokkaContext,
+    private val logger: DokkaLogger
+) : DocCommentParser {
+
+    override fun canParse(docComment: DocComment): Boolean {
+        return docComment is KotlinDocComment
+    }
+
+    override fun parse(docComment: DocComment, context: PsiNamedElement): DocumentationNode {
+        val kotlinDocComment = docComment as KotlinDocComment
+        return parseDocumentation(kotlinDocComment)
+    }
+
+    fun parseDocumentation(element: KotlinDocComment, parseWithChildren: Boolean = true): DocumentationNode {
+        val sourceSet = context.configuration.sourceSets.let { sourceSets ->
+            sourceSets.firstOrNull { it.sourceSetID.sourceSetName == "jvmMain" }
+                ?: sourceSets.first { it.analysisPlatform == Platform.jvm }
+        }
+        val kdocFinder = context.plugin().querySingle { kdocFinder }
+        return parseFromKDocTag(
+            kDocTag = element.comment,
+            externalDri = { link: String ->
+                try {
+                    kdocFinder.resolveKDocLink(element.descriptor, link, sourceSet)
+                        .firstOrNull()
+                        ?.let { DRI.from(it) }
+                } catch (e1: IllegalArgumentException) {
+                    logger.warn("Couldn't resolve link for $link")
+                    null
+                }
+            },
+            kdocLocation = null,
+            parseWithChildren = parseWithChildren
+        )
+    }
+}
+
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt
new file mode 100644
index 00000000000..3a1972c5890
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt
@@ -0,0 +1,31 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java
+
+import org.jetbrains.dokka.analysis.java.DocumentationContent
+import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin
+import org.jetbrains.dokka.analysis.java.doctag.DocTagParserContext
+import org.jetbrains.dokka.analysis.java.doctag.InheritDocTagContentProvider
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
+
+internal class KotlinInheritDocTagContentProvider(
+    context: DokkaContext
+) : InheritDocTagContentProvider {
+
+    val parser: KotlinDocCommentParser by lazy {
+        context.plugin().query { docCommentParsers }
+            .single { it is KotlinDocCommentParser } as KotlinDocCommentParser
+    }
+
+    override fun canConvert(content: DocumentationContent): Boolean = content is DescriptorDocumentationContent
+
+    override fun convertToHtml(content: DocumentationContent, docTagParserContext: DocTagParserContext): String {
+        val descriptorContent = content as DescriptorDocumentationContent
+        val inheritedDocNode = parser.parseDocumentation(
+            KotlinDocComment(descriptorContent.element, descriptorContent.descriptor),
+            parseWithChildren = false
+        )
+        val id = docTagParserContext.store(inheritedDocNode)
+        return """"""
+    }
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt
new file mode 100644
index 00000000000..e1dec28c421
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt
@@ -0,0 +1,12 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
+
+// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5
+internal inline fun  Iterable.firstNotNullOfOrNull(transform: (T) -> R?): R? {
+    for (element in this) {
+        val result = transform(element)
+        if (result != null) {
+            return result
+        }
+    }
+    return null
+}
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt
similarity index 93%
rename from plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt
index 41ab20397fa..730fc2ead6e 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.base.translators.descriptors
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
 import com.intellij.psi.PsiElement
 import com.intellij.psi.PsiNamedElement
@@ -8,15 +8,14 @@ import kotlinx.coroutines.async
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.runBlocking
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
-import org.jetbrains.dokka.analysis.DescriptorDocumentableSource
-import org.jetbrains.dokka.analysis.DokkaResolutionFacade
-import org.jetbrains.dokka.analysis.KotlinAnalysis
-import org.jetbrains.dokka.analysis.from
-import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.base.parsers.MarkdownParser
-import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser
-import org.jetbrains.dokka.base.translators.typeConstructorsBeingExceptions
-import org.jetbrains.dokka.base.translators.unquotedValue
+import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin
+import org.jetbrains.dokka.analysis.java.parsers.JavadocParser
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.DescriptorDocumentableSource
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.KotlinAnalysis
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
 import org.jetbrains.dokka.links.*
 import org.jetbrains.dokka.links.Callable
 import org.jetbrains.dokka.model.*
@@ -27,6 +26,7 @@ import org.jetbrains.dokka.model.doc.*
 import org.jetbrains.dokka.model.properties.PropertyContainer
 import org.jetbrains.dokka.plugability.DokkaContext
 import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
 import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTranslator
 import org.jetbrains.dokka.utilities.DokkaLogger
@@ -43,8 +43,6 @@ import org.jetbrains.kotlin.descriptors.ClassKind
 import org.jetbrains.kotlin.descriptors.annotations.Annotated
 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
 import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
-import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
 import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
 import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
 import org.jetbrains.kotlin.load.kotlin.toSourceElement
@@ -68,8 +66,6 @@ import org.jetbrains.kotlin.resolve.source.PsiSourceFile
 import org.jetbrains.kotlin.types.*
 import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
 import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
-import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
-import org.jetbrains.kotlin.utils.addToStdlib.safeAs
 import java.nio.file.Paths
 import org.jetbrains.kotlin.resolve.constants.AnnotationValue as ConstantsAnnotationValue
 import org.jetbrains.kotlin.resolve.constants.ArrayValue as ConstantsArrayValue
@@ -84,22 +80,30 @@ import org.jetbrains.kotlin.resolve.constants.NullValue as ConstantsNullValue
 import org.jetbrains.kotlin.resolve.constants.UIntValue as ConstantsUIntValue
 import org.jetbrains.kotlin.resolve.constants.ULongValue as ConstantsULongValue
 
-class DefaultDescriptorToDocumentableTranslator(
+internal class DefaultDescriptorToDocumentableTranslator(
     private val context: DokkaContext
 ) : AsyncSourceToDocumentableTranslator, ExternalClasslikesTranslator {
 
-    private val kotlinAnalysis: KotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+    private val kotlinAnalysis: KotlinAnalysis = context.plugin().querySingle { kotlinAnalysis }
+    private val kdocFinder: KDocFinder = context.plugin().querySingle { kdocFinder }
 
     override suspend fun invokeSuspending(sourceSet: DokkaSourceSet, context: DokkaContext): DModule {
-        val (environment, facade) = kotlinAnalysis[sourceSet]
+        val analysisContext = kotlinAnalysis[sourceSet]
+        val environment = analysisContext.environment
         val packageFragments = environment.getSourceFiles().asSequence()
             .map { it.packageFqName }
             .distinct()
-            .mapNotNull { facade.resolveSession.getPackageFragment(it) }
+            .mapNotNull { analysisContext.resolveSession.getPackageFragment(it) }
             .toList()
 
-        return DokkaDescriptorVisitor(sourceSet, kotlinAnalysis[sourceSet].facade, context.logger).run {
-            packageFragments.mapNotNull { it.safeAs() }.parallelMap {
+        val javadocParser = JavadocParser(
+            docCommentParsers = context.plugin().query { docCommentParsers },
+            docCommentFinder = context.plugin().docCommentFinder
+        )
+
+
+        return DokkaDescriptorVisitor(sourceSet, kdocFinder, kotlinAnalysis[sourceSet], context.logger, javadocParser).run {
+            packageFragments.parallelMap {
                 visitPackageFragmentDescriptor(
                     it
                 )
@@ -118,27 +122,33 @@ class DefaultDescriptorToDocumentableTranslator(
     override fun translateClassDescriptor(descriptor: ClassDescriptor, sourceSet: DokkaSourceSet): DClasslike {
         val driInfo = DRI.from(descriptor.parents.first()).withEmptyInfo()
 
+        val javadocParser = JavadocParser(
+            docCommentParsers = context.plugin().query { docCommentParsers },
+            docCommentFinder = context.plugin().docCommentFinder
+        )
+
         return runBlocking(Dispatchers.Default) {
-            DokkaDescriptorVisitor(sourceSet, kotlinAnalysis[sourceSet].facade, context.logger)
+            DokkaDescriptorVisitor(sourceSet, kdocFinder, kotlinAnalysis[sourceSet], context.logger, javadocParser)
                 .visitClassDescriptor(descriptor, driInfo)
         }
     }
 }
 
-data class DRIWithPlatformInfo(
+internal data class DRIWithPlatformInfo(
     val dri: DRI,
     val actual: SourceSetDependent
 )
 
-fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, emptyMap())
+internal fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, emptyMap())
 
 private class DokkaDescriptorVisitor(
     private val sourceSet: DokkaSourceSet,
-    private val resolutionFacade: DokkaResolutionFacade,
-    private val logger: DokkaLogger
+    private val kDocFinder: KDocFinder,
+    private val analysisContext: AnalysisContext,
+    private val logger: DokkaLogger,
+    private val javadocParser: JavadocParser
 ) {
-    private val javadocParser = JavadocParser(logger, resolutionFacade)
-    private val syntheticDocProvider = SyntheticDescriptorDocumentationProvider(resolutionFacade)
+    private val syntheticDocProvider = SyntheticDescriptorDocumentationProvider(kDocFinder, sourceSet)
 
     private fun Collection.filterDescriptorsInSourceSet() = filter {
         it.toSourceElement.containingFile.toString().let { path ->
@@ -462,7 +472,7 @@ private class DokkaDescriptorVisitor(
         // example - generated getter that comes with data classes
         suspend fun getDescriptorGetter() =
             descriptor.accessors
-                .firstIsInstanceOrNull()
+                .filterIsInstance().firstOrNull()
                 ?.let {
                     visitPropertyAccessorDescriptor(it, descriptor, dri, inheritedFrom)
                 }
@@ -473,7 +483,7 @@ private class DokkaDescriptorVisitor(
         // example - generated setter that comes with data classes
         suspend fun getDescriptorSetter() =
             descriptor.accessors
-                .firstIsInstanceOrNull()
+                .filterIsInstance().firstOrNull()
                 ?.let {
                     visitPropertyAccessorDescriptor(it, descriptor, dri, inheritedFrom)
                 }
@@ -512,6 +522,7 @@ private class DokkaDescriptorVisitor(
                         descriptor.getDefaultValue()?.let { DefaultValue(it.toSourceSetDependent()) },
                         inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) },
                         takeIf { descriptor.isVar(getter, setter) }?.let { IsVar },
+                        takeIf { descriptor.findPsi() is KtParameter }?.let { IsAlsoParameter(listOf(sourceSet)) }
                     )
                 )
             )
@@ -958,7 +969,7 @@ private class DokkaDescriptorVisitor(
 
     private fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? =
         mapNotNull { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name")
-            .safeAs()?.value?.let { unquotedValue(it) }
+            .let { it as? StringValue }?.value?.let { unquotedValue(it) }
 
     private suspend fun KotlinType.toBound(): Bound {
         suspend fun  annotations(): PropertyContainer =
@@ -1025,30 +1036,41 @@ private class DokkaDescriptorVisitor(
         return effectiveReferencedDescriptors.firstOrNull()?.let { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
     }
 
-    private fun DeclarationDescriptor.getDocumentation() = (findKDoc(::descriptorToAnyDeclaration)?.let {
-        MarkdownParser.parseFromKDocTag(
-            kDocTag = it,
-            externalDri = { link: String ->
-                try {
-                    resolveKDocLink(
-                        context = resolutionFacade.resolveSession.bindingContext,
-                        resolutionFacade = resolutionFacade,
-                        fromDescriptor = this,
-                        fromSubjectOfTag = null,
-                        qualifiedName = link.split('.')
-                    ).firstOrNull()?.let { DRI.from(it) }
-                } catch (e1: IllegalArgumentException) {
-                    logger.warn("Couldn't resolve link for $link")
-                    null
-                }
-            },
-            kdocLocation = toSourceElement.containingFile.name?.let {
-                val fqName = fqNameOrNull()?.asString()
-                if (fqName != null) "$it/$fqName"
-                else it
-            }
-        )
-    } ?: getJavaDocs())?.takeIf { it.children.isNotEmpty() }
+    private fun DeclarationDescriptor.getDocumentation(): DocumentationNode? {
+        val find = with(kDocFinder) {
+            find(::descriptorToAnyDeclaration)
+        }
+
+        return (find?.let {
+                parseFromKDocTag(
+                    kDocTag = it,
+                    externalDri = { link: String ->
+                        try {
+                            val kdocLink = with(kDocFinder) {
+                                resolveKDocLink(
+                                    fromDescriptor = this@getDocumentation,
+                                    qualifiedName = link,
+                                    sourceSet = sourceSet
+                                )
+                            }
+                            kdocLink.firstOrNull()?.let {
+                                DRI.from(
+                                    it
+                                )
+                            }
+                        } catch (e1: IllegalArgumentException) {
+                            logger.warn("Couldn't resolve link for $link")
+                            null
+                        }
+                    },
+                    kdocLocation = toSourceElement.containingFile.name?.let {
+                        val fqName = fqNameOrNull()?.asString()
+                        if (fqName != null) "$it/$fqName"
+                        else it
+                    }
+                )
+            } ?: getJavaDocs())?.takeIf { it.children.isNotEmpty() }
+        }
 
     private fun DeclarationDescriptor.getJavaDocs(): DocumentationNode? {
         val overriddenDescriptors = (this as? CallableDescriptor)?.overriddenDescriptors ?: emptyList()
@@ -1189,11 +1211,11 @@ private class DokkaDescriptorVisitor(
 
     private fun ClassDescriptor.getAppliedConstructorParameters() =
         (source as PsiSourceElement).psi?.children?.flatMap {
-            it.safeAs()?.initializersAsExpression().orEmpty()
+            (it as? KtInitializerList)?.initializersAsExpression().orEmpty()
         }.orEmpty()
 
     private fun KtInitializerList.initializersAsExpression() =
-        initializers.firstIsInstanceOrNull()
+        initializers.filterIsInstance().firstOrNull()
             ?.getValueArgumentsInParentheses()
             ?.map { it.getArgumentExpression()?.toDefaultValueExpression() ?: ComplexExpression("") }
             .orEmpty()
@@ -1238,7 +1260,9 @@ private class DokkaDescriptorVisitor(
         (source.containingFile as? PsiSourceFile)?.psiFile as? KtFile
 
     private suspend fun DeclarationDescriptorWithSource.fileLevelAnnotations() = ktFile()
-        ?.let { file -> resolutionFacade.resolveSession.getFileAnnotations(file) }
+        ?.let { file ->
+            analysisContext.resolveSession.getFileAnnotations(file)
+        }
         ?.toList()
         ?.parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) }
         .orEmpty()
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultExternalDocumentablesProvider.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt
similarity index 70%
rename from plugins/base/src/main/kotlin/translators/descriptors/DefaultExternalDocumentablesProvider.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt
index 05982301e0b..bde26983a22 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultExternalDocumentablesProvider.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt
@@ -1,12 +1,13 @@
-package org.jetbrains.dokka.base.translators.descriptors
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
-import org.jetbrains.dokka.base.DokkaBase
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.DClasslike
 import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.kotlin.analysis.kotlin.ExternalDocumentablesProvider
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
@@ -14,16 +15,16 @@ import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.resolve.scopes.MemberScope
 import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
 
-class DefaultExternalDocumentablesProvider(context: DokkaContext) : ExternalDocumentablesProvider {
-    private val analysis = context.plugin().querySingle { kotlinAnalysis }
+internal class DefaultExternalDocumentablesProvider(context: DokkaContext) : ExternalDocumentablesProvider {
+    private val analysis = context.plugin().querySingle { kotlinAnalysis }
 
-    private val translator = context.plugin().querySingle { externalClasslikesTranslator }
+    private val translator: ExternalClasslikesTranslator = DefaultDescriptorToDocumentableTranslator(context)
 
     override fun findClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? {
         val pkg = dri.packageName?.let { FqName(it) } ?: FqName.ROOT
         val names = dri.classNames?.split('.') ?: return null
 
-        val packageDsc = analysis[sourceSet].facade.moduleDescriptor.getPackage(pkg)
+        val packageDsc = analysis[sourceSet].moduleDescriptor.getPackage(pkg)
         val classDsc = names.fold(packageDsc) { dsc, name ->
             dsc?.scope?.getDescriptorsFiltered { it.identifier == name }
                 ?.filterIsInstance()
@@ -39,4 +40,4 @@ class DefaultExternalDocumentablesProvider(context: DokkaContext) : ExternalDocu
             is ClassDescriptor -> unsubstitutedMemberScope
             else -> throw IllegalArgumentException("Unexpected type of descriptor: ${this::class}")
         }
-}
\ No newline at end of file
+}
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DescriptorAccessorConventionUtil.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt
similarity index 97%
rename from plugins/base/src/main/kotlin/translators/descriptors/DescriptorAccessorConventionUtil.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt
index 292dbfcad51..fcb0b83d994 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DescriptorAccessorConventionUtil.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt
@@ -1,6 +1,5 @@
-package org.jetbrains.dokka.base.translators.descriptors
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
-import org.jetbrains.dokka.base.translators.firstNotNullOfOrNull
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
 import org.jetbrains.kotlin.descriptors.PropertyDescriptor
 import org.jetbrains.kotlin.load.java.JvmAbi
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/ExternalClasslikesTranslator.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt
similarity index 74%
rename from plugins/base/src/main/kotlin/translators/descriptors/ExternalClasslikesTranslator.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt
index a5385c46548..0b4b4442be3 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/ExternalClasslikesTranslator.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.base.translators.descriptors
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
 import org.jetbrains.dokka.model.DClasslike
@@ -7,6 +7,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
 /**
  * Service translating [ClassDescriptor]s of symbols defined outside of documented project to [DClasslike]s.
  */
-fun interface ExternalClasslikesTranslator {
+internal fun interface ExternalClasslikesTranslator {
     fun translateClassDescriptor(descriptor: ClassDescriptor, sourceSet: DokkaSourceSet): DClasslike
-}
\ No newline at end of file
+}
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt
new file mode 100644
index 00000000000..65813cbf889
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt
@@ -0,0 +1,101 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
+
+import com.intellij.psi.PsiElement
+import org.jetbrains.dokka.analysis.markdown.MarkdownParser
+import org.jetbrains.dokka.analysis.markdown.MarkdownParser.Companion.fqDeclarationName
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.doc.*
+import org.jetbrains.dokka.model.doc.Suppress
+import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+
+internal fun parseFromKDocTag(
+    kDocTag: KDocTag?,
+    externalDri: (String) -> DRI?,
+    kdocLocation: String?,
+    parseWithChildren: Boolean = true
+): DocumentationNode {
+    return if (kDocTag == null) {
+        DocumentationNode(emptyList())
+    } else {
+        fun parseStringToDocNode(text: String) =
+            MarkdownParser(externalDri, kdocLocation).parseStringToDocNode(text)
+
+        fun pointedLink(tag: KDocTag): DRI? = (parseStringToDocNode("[${tag.getSubjectName()}]")).let {
+            val link = it.children[0].children[0]
+            if (link is DocumentationLink) link.dri else null
+        }
+
+        val allTags =
+            listOf(kDocTag) + if (kDocTag.canHaveParent() && parseWithChildren) getAllKDocTags(findParent(kDocTag)) else emptyList()
+        DocumentationNode(
+            allTags.map {
+                when (it.knownTag) {
+                    null -> if (it.name == null) Description(parseStringToDocNode(it.getContent())) else CustomTagWrapper(
+                        parseStringToDocNode(it.getContent()),
+                        it.name!!
+                    )
+                    KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent()))
+                    KDocKnownTag.THROWS -> {
+                        val dri = pointedLink(it)
+                        Throws(
+                            parseStringToDocNode(it.getContent()),
+                            dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
+                            dri,
+                        )
+                    }
+                    KDocKnownTag.EXCEPTION -> {
+                        val dri = pointedLink(it)
+                        Throws(
+                            parseStringToDocNode(it.getContent()),
+                            dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
+                            dri
+                        )
+                    }
+                    KDocKnownTag.PARAM -> Param(
+                        parseStringToDocNode(it.getContent()),
+                        it.getSubjectName().orEmpty()
+                    )
+                    KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent()))
+                    KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent()))
+                    KDocKnownTag.SEE -> {
+                        val dri = pointedLink(it)
+                        See(
+                            parseStringToDocNode(it.getContent()),
+                            dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
+                            dri,
+                        )
+                    }
+                    KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent()))
+                    KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent()))
+                    KDocKnownTag.PROPERTY -> Property(
+                        parseStringToDocNode(it.getContent()),
+                        it.getSubjectName().orEmpty()
+                    )
+                    KDocKnownTag.SAMPLE -> Sample(
+                        parseStringToDocNode(it.getContent()),
+                        it.getSubjectName().orEmpty()
+                    )
+                    KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent()))
+                }
+            }
+        )
+    }
+}
+
+//Horrible hack but since link resolution is passed as a function i am not able to resolve them otherwise
+@kotlin.Suppress("DeprecatedCallableAddReplaceWith")
+@Deprecated("This function makes wrong assumptions and is missing a lot of corner cases related to generics, " +
+        "parameters and static members. This is not supposed to be public API and will not be supported in the future")
+internal fun DRI.fqName(): String? = "$packageName.$classNames".takeIf { packageName != null && classNames != null }
+
+private fun findParent(kDoc: PsiElement): PsiElement =
+    if (kDoc.canHaveParent()) findParent(kDoc.parent) else kDoc
+
+private fun PsiElement.canHaveParent(): Boolean = this is KDocSection && knownTag != KDocKnownTag.PROPERTY
+
+private fun getAllKDocTags(kDocImpl: PsiElement): List =
+    kDocImpl.children.filterIsInstance().filterNot { it is KDocSection } + kDocImpl.children.flatMap {
+        getAllKDocTags(it)
+    }
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt
similarity index 71%
rename from plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt
index c96b888a94a..f5a5f0b38c0 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt
@@ -1,20 +1,21 @@
-package org.jetbrains.dokka.base.translators.descriptors
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
-import org.jetbrains.dokka.analysis.DokkaResolutionFacade
-import org.jetbrains.dokka.analysis.from
-import org.jetbrains.dokka.base.parsers.MarkdownParser
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.from
+import org.jetbrains.dokka.analysis.markdown.MarkdownParser
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.doc.DocumentationNode
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
 import org.jetbrains.kotlin.resolve.DescriptorFactory
 
 private const val ENUM_VALUEOF_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumValueOf.kt.template"
 private const val ENUM_VALUES_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumValues.kt.template"
 
- internal class SyntheticDescriptorDocumentationProvider(
-    private val resolutionFacade: DokkaResolutionFacade
+internal class SyntheticDescriptorDocumentationProvider(
+    private val kDocFinder: KDocFinder,
+    private val sourceSet: DokkaConfiguration.DokkaSourceSet
 ) {
     fun isDocumented(descriptor: DeclarationDescriptor): Boolean = descriptor is FunctionDescriptor
             && (DescriptorFactory.isEnumValuesMethod(descriptor) || DescriptorFactory.isEnumValueOfMethod(descriptor))
@@ -37,11 +38,9 @@ private const val ENUM_VALUES_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumValues.kt.te
     private fun loadContent(filePath: String): String? = javaClass.getResource(filePath)?.readText()
 
     private fun resolveLink(descriptor: DeclarationDescriptor, link: String): DRI? =
-        resolveKDocLink(
-            resolutionFacade.resolveSession.bindingContext,
-            resolutionFacade,
-            descriptor,
-            null,
-            link.split('.')
+        kDocFinder.resolveKDocLink(
+            fromDescriptor = descriptor,
+            qualifiedName = link,
+            sourceSet = sourceSet
         ).firstOrNull()?.let { DRI.from(it) }
 }
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt
new file mode 100644
index 00000000000..70254566643
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt
@@ -0,0 +1,3 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
+
+internal fun unquotedValue(value: String): String = value.removeSurrounding("\"")
diff --git a/plugins/base/src/main/kotlin/translators/isException.kt b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt
similarity index 90%
rename from plugins/base/src/main/kotlin/translators/isException.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt
index d148cd34b96..710846b3bc2 100644
--- a/plugins/base/src/main/kotlin/translators/isException.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.base.translators
+package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator
 
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.AncestryNode
diff --git a/analysis/kotlin-analysis-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/analysis/kotlin-analysis-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000000..c7a8a233efa
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin
diff --git a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt b/analysis/kotlin-analysis-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt
similarity index 94%
rename from plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt
rename to analysis/kotlin-analysis-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt
index b6f9307fc09..ac1a9d32b41 100644
--- a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt
+++ b/analysis/kotlin-analysis-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt
@@ -1,17 +1,17 @@
-package parsers
+package org.jetbrains.dokka.analysis.kotlin.descriptors
 
-import org.intellij.markdown.MarkdownElementTypes
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.*
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Package
+
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.ModuleAndPackageDocumentation.Classifier.*
+import org.jetbrains.dokka.analysis.markdown.MARKDOWN_FILE_NAME
 import org.jetbrains.dokka.model.doc.*
 import org.jetbrains.dokka.utilities.DokkaLogger
-import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertThrows
 import org.junit.jupiter.api.io.TempDir
 import java.nio.file.Path
+import kotlin.test.assertEquals
 
 class ParseModuleAndPackageDocumentationFragmentsTest {
 
@@ -257,14 +257,14 @@ class ParseModuleAndPackageDocumentationFragmentsTest {
                                     Text("@Smth")
                                 )
                             )
-                        ), name = MarkdownElementTypes.MARKDOWN_FILE.name
+                        ), name = MARKDOWN_FILE_NAME
                     )
                 ),
                 Author(
                     CustomDocTag(
                         listOf(
                             P(listOf(Text("Smb")))
-                        ), name = MarkdownElementTypes.MARKDOWN_FILE.name
+                        ), name = MARKDOWN_FILE_NAME
                     )
                 )
             )
diff --git a/analysis/kotlin-analysis-descriptors/ide/api/ide.api b/analysis/kotlin-analysis-descriptors/ide/api/ide.api
new file mode 100644
index 00000000000..a59658a3693
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/ide/api/ide.api
@@ -0,0 +1,4 @@
+public final class org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+	public fun  ()V
+}
+
diff --git a/analysis/kotlin-analysis-descriptors/ide/build.gradle.kts b/analysis/kotlin-analysis-descriptors/ide/build.gradle.kts
new file mode 100644
index 00000000000..6a47498499a
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/ide/build.gradle.kts
@@ -0,0 +1,22 @@
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+}
+
+dependencies {
+    compileOnly(projects.core)
+    compileOnly(projects.analysis.kotlinAnalysisApi)
+
+    implementation(projects.analysis.kotlinAnalysisDescriptors.compiler)
+    implementation(projects.analysis.markdown)
+
+    api(libs.kotlin.idePlugin.common)
+    api(libs.kotlin.idePlugin.idea)
+    api(libs.kotlin.idePlugin.core)
+    api(libs.kotlin.idePlugin.native)
+
+    // TODO [beresnev] needed for CommonIdePlatformKind, describe
+    implementation("org.jetbrains.kotlin:jps-common:213-1.6.21-release-334-IJ6777.52")
+
+    // TODO [beresnev] get rid of it
+    compileOnly(libs.kotlinx.coroutines.core)
+}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt
similarity index 90%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt
rename to analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt
index e2cd328ac96..d7069656107 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CoreKotlinCacheService.kt
+++ b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt
@@ -1,4 +1,4 @@
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
 
 import com.intellij.psi.PsiFile
 import org.jetbrains.kotlin.analyzer.ModuleInfo
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.psi.KtElement
 import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
 
 
-class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService {
+internal class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService {
     override fun getResolutionFacade(elements: List): ResolutionFacade {
         return resolutionFacade
     }
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DokkaResolutionFacade.kt b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt
similarity index 98%
rename from kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DokkaResolutionFacade.kt
rename to analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt
index b278ef6ed35..e2253b99ab6 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DokkaResolutionFacade.kt
+++ b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt
@@ -1,6 +1,6 @@
 @file:OptIn(FrontendInternals::class)
 
-package org.jetbrains.dokka.analysis
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
 
 import com.google.common.collect.ImmutableMap
 import com.intellij.openapi.project.Project
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.types.KotlinType
 import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
 import org.jetbrains.kotlin.util.slicedMap.WritableSlice
 
-class DokkaResolutionFacade(
+internal class DokkaResolutionFacade(
     override val project: Project,
     override val moduleDescriptor: ModuleDescriptor,
     val resolverForModule: ResolverForModule
diff --git a/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt
new file mode 100644
index 00000000000..48a4d3c428c
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt
@@ -0,0 +1,207 @@
+package org.jetbrains.dokka.analysis.kotlin.descriptors.ide
+
+import com.intellij.mock.MockApplication
+import com.intellij.mock.MockComponentManager
+import com.intellij.mock.MockProject
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.*
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext
+import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment
+import org.jetbrains.dokka.plugability.*
+import org.jetbrains.kotlin.analyzer.ResolverForModule
+import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
+import org.jetbrains.kotlin.caches.resolve.*
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
+import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
+import org.jetbrains.kotlin.ide.konan.NativePlatformKindResolution
+import org.jetbrains.kotlin.idea.kdoc.findKDoc
+import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache
+import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
+import org.jetbrains.kotlin.idea.klib.getCompatibilityInfo
+import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
+import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.platform.IdePlatformKind
+import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
+import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
+import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
+import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
+import org.jetbrains.kotlin.resolve.lazy.ResolveSession
+import org.jetbrains.kotlin.storage.StorageManager
+import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink as ideResolveKDocLink
+
+internal class IdeSearchHelpers : SearchHelpers {
+    override fun KtDeclaration.findDescriptor(): DeclarationDescriptor? {
+        return this.descriptor
+    }
+}
+
+internal class IdePluginKDocFinder(
+    private val context: DokkaContext
+) : KDocFinder {
+
+    override fun KtElement.findKDoc(): KDocTag? {
+        return this.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) }
+    }
+
+    override fun DeclarationDescriptor.find(descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement?): KDocTag? {
+        return this.findKDoc(descriptorToPsi)
+    }
+
+    override fun resolveKDocLink(
+        fromDescriptor: DeclarationDescriptor,
+        qualifiedName: String,
+        sourceSet: DokkaConfiguration.DokkaSourceSet,
+        emptyBindingContext: Boolean
+    ): Collection {
+        val facadeAnalysisContext = context
+            .plugin()
+            .querySingle { kotlinAnalysis }[sourceSet] as ResolutionFacadeAnalysisContext
+
+        return ideResolveKDocLink(
+            context = if (emptyBindingContext) BindingContext.EMPTY else facadeAnalysisContext.resolveSession.bindingContext,
+            resolutionFacade = facadeAnalysisContext.facade,
+            fromDescriptor = fromDescriptor,
+            fromSubjectOfTag = null,
+            qualifiedName = qualifiedName.split('.')
+        )
+    }
+}
+
+internal class AnalysisContextCreatorImpl : AnalysisContextCreator {
+    override fun create(
+        project: MockProject,
+        moduleDescriptor: ModuleDescriptor,
+        moduleResolver: ResolverForModule,
+        kotlinEnvironment: KotlinCoreEnvironment,
+        analysisEnvironment: AnalysisEnvironment,
+    ): AnalysisContext {
+        val facade = DokkaResolutionFacade(project, moduleDescriptor, moduleResolver)
+        val projectComponentManager = project as MockComponentManager
+        projectComponentManager.registerService(
+            KotlinCacheService::class.java,
+            CoreKotlinCacheService(facade)
+        )
+        return ResolutionFacadeAnalysisContext(facade, kotlinEnvironment, analysisEnvironment)
+    }
+}
+
+internal class KLibServiceImpl : KLibService {
+    override fun KotlinLibrary.createPackageFragmentProvider(
+        storageManager: StorageManager,
+        metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory,
+        languageVersionSettings: LanguageVersionSettings,
+        moduleDescriptor: ModuleDescriptor,
+        lookupTracker: LookupTracker,
+    ): PackageFragmentProvider? {
+        return this.createKlibPackageFragmentProvider(
+            storageManager, metadataModuleDescriptorFactory, languageVersionSettings, moduleDescriptor, lookupTracker
+        )
+    }
+
+    override fun isAnalysisCompatible(kotlinLibrary: KotlinLibrary): Boolean {
+        return kotlinLibrary.getCompatibilityInfo().isCompatible
+    }
+}
+
+internal class ResolutionFacadeAnalysisContext(
+    val facade: DokkaResolutionFacade,
+
+    private val kotlinEnvironment: KotlinCoreEnvironment,
+    private val analysisEnvironment: AnalysisEnvironment
+) : AnalysisContext {
+    private var isClosed: Boolean = false
+
+    override val environment: KotlinCoreEnvironment
+        get() = kotlinEnvironment.takeUnless { isClosed }
+            ?: throw IllegalStateException("AnalysisEnvironment is already closed")
+
+    override val resolveSession: ResolveSession = facade.resolveSession
+    override val moduleDescriptor: ModuleDescriptor = facade.moduleDescriptor
+    override val project: Project = facade.project
+
+    override fun close() {
+        isClosed = true
+        analysisEnvironment.dispose()
+    }
+}
+
+internal class CompilerExtensionPointProviderImpl : CompilerExtensionPointProvider {
+    override fun get(): List {
+
+        @Suppress("UNCHECKED_CAST")
+        val idePlatformKind = CompilerExtensionPointProvider.CompilerExtensionPoint(
+            ApplicationExtensionDescriptor("org.jetbrains.kotlin.idePlatformKind", IdePlatformKind::class.java) as  ApplicationExtensionDescriptor,
+            listOf(
+                CommonIdePlatformKind,
+                JvmIdePlatformKind,
+                JsIdePlatformKind,
+                NativeIdePlatformKind
+            )
+        )
+
+        @Suppress("UNCHECKED_CAST")
+        val resolution = CompilerExtensionPointProvider.CompilerExtensionPoint(
+            IdePlatformKindResolution as ApplicationExtensionDescriptor,
+            listOf(
+                CommonPlatformKindResolution(),
+                JvmPlatformKindResolution(),
+                JsPlatformKindResolution(),
+                NativePlatformKindResolution()
+            )
+        )
+
+        return listOf(idePlatformKind, resolution)
+    }
+}
+
+internal class MockApplicationHackImpl : MockApplicationHack {
+    override fun hack(mockApplication: MockApplication) {
+        if (mockApplication.getService(KlibLoadingMetadataCache::class.java) == null)
+            mockApplication.registerService(KlibLoadingMetadataCache::class.java, KlibLoadingMetadataCache())
+    }
+}
+
+@InternalDokkaApi
+class IdeDescriptorAnalysisPlugin : DokkaPlugin() {
+
+    internal val idePluginKDocFinder by extending {
+        plugin().kdocFinder providing ::IdePluginKDocFinder
+    }
+
+    internal val idePluginSearchHelpers by extending {
+        plugin().searchHelpers providing { IdeSearchHelpers() }
+    }
+
+    internal val klibServiceImpl by extending {
+        plugin().klibService providing { KLibServiceImpl() }
+    }
+
+    internal val compilerExtensionPointProviderImpl by extending {
+        plugin().compilerExtensionPointProvider providing { CompilerExtensionPointProviderImpl() }
+    }
+
+    internal val mockApplicationHackImpl by extending {
+        plugin().mockApplicationHack providing { MockApplicationHackImpl() }
+    }
+
+    internal val analysisContextImpl by extending {
+        plugin().analysisContextCreator providing { AnalysisContextCreatorImpl() }
+    }
+
+    @OptIn(DokkaPluginApiPreview::class)
+    override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/analysis/kotlin-analysis-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/analysis/kotlin-analysis-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000000..f993dcb1ddb
--- /dev/null
+++ b/analysis/kotlin-analysis-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.analysis.kotlin.descriptors.ide.IdeDescriptorAnalysisPlugin
diff --git a/analysis/kotlin-analysis-symbols/build.gradle.kts b/analysis/kotlin-analysis-symbols/build.gradle.kts
new file mode 100644
index 00000000000..f9be6a01861
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/build.gradle.kts
@@ -0,0 +1,31 @@
+import org.jetbrains.DokkaPublicationBuilder
+import org.jetbrains.registerDokkaArtifactPublication
+
+plugins {
+    id("org.jetbrains.conventions.base-java")
+    id("org.jetbrains.conventions.maven-publish")
+    id("com.github.johnrengelman.shadow")
+}
+
+dependencies {
+    implementation(projects.analysis.kotlinAnalysisApi)
+    implementation(projects.analysis.kotlinAnalysisSymbols.compiler)
+    implementation(projects.analysis.kotlinAnalysisSymbols.ide)
+}
+
+tasks {
+    shadowJar {
+        val dokka_version: String by project
+        archiveFileName.set("dokka-analysis-symbols-$dokka_version.jar")
+        archiveClassifier.set("")
+
+        // service files are merged to make sure all Dokka plugins
+        // from the dependencies are loaded, and not just a single one.
+        mergeServiceFiles()
+    }
+}
+
+registerDokkaArtifactPublication("kotlinAnalysisSymbols") {
+    artifactId = "kotlin-analysis-symbols"
+    component = DokkaPublicationBuilder.Component.Shadow
+}
diff --git a/analysis/kotlin-analysis-symbols/compiler/api/compiler.api b/analysis/kotlin-analysis-symbols/compiler/api/compiler.api
new file mode 100644
index 00000000000..39870f571ca
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/compiler/api/compiler.api
@@ -0,0 +1,4 @@
+public final class org/jetbrains/dokka/analysis/kotlin/symbols/compiler/CompilerSymbolsAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+	public fun  ()V
+}
+
diff --git a/analysis/kotlin-analysis-symbols/compiler/build.gradle.kts b/analysis/kotlin-analysis-symbols/compiler/build.gradle.kts
new file mode 100644
index 00000000000..b1618935c23
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/compiler/build.gradle.kts
@@ -0,0 +1,13 @@
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+}
+
+dependencies {
+    compileOnly(projects.core)
+    compileOnly(projects.analysis.kotlinAnalysisApi)
+
+    // TODO
+
+    // TODO [beresnev] get rid of it
+    compileOnly(libs.kotlinx.coroutines.core)
+}
diff --git a/analysis/kotlin-analysis-symbols/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/compiler/CompilerSymbolsAnalysisPlugin.kt b/analysis/kotlin-analysis-symbols/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/compiler/CompilerSymbolsAnalysisPlugin.kt
new file mode 100644
index 00000000000..4a39e0d81ee
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/compiler/CompilerSymbolsAnalysisPlugin.kt
@@ -0,0 +1,11 @@
+package org.jetbrains.dokka.analysis.kotlin.symbols.compiler
+
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
+
+class CompilerSymbolsAnalysisPlugin : DokkaPlugin() {
+
+    @OptIn(DokkaPluginApiPreview::class)
+    override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/analysis/kotlin-analysis-symbols/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/analysis/kotlin-analysis-symbols/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000000..47163f6e211
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.analysis.kotlin.symbols.compiler.CompilerSymbolsAnalysisPlugin
diff --git a/analysis/kotlin-analysis-symbols/ide/api/ide.api b/analysis/kotlin-analysis-symbols/ide/api/ide.api
new file mode 100644
index 00000000000..9be46c0b5f6
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/ide/api/ide.api
@@ -0,0 +1,4 @@
+public final class org/jetbrains/dokka/analysis/kotlin/symbols/ide/IdeSymbolsAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
+	public fun  ()V
+}
+
diff --git a/analysis/kotlin-analysis-symbols/ide/build.gradle.kts b/analysis/kotlin-analysis-symbols/ide/build.gradle.kts
new file mode 100644
index 00000000000..b1618935c23
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/ide/build.gradle.kts
@@ -0,0 +1,13 @@
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+}
+
+dependencies {
+    compileOnly(projects.core)
+    compileOnly(projects.analysis.kotlinAnalysisApi)
+
+    // TODO
+
+    // TODO [beresnev] get rid of it
+    compileOnly(libs.kotlinx.coroutines.core)
+}
diff --git a/analysis/kotlin-analysis-symbols/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/ide/IdeSymbolsAnalysisPlugin.kt b/analysis/kotlin-analysis-symbols/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/ide/IdeSymbolsAnalysisPlugin.kt
new file mode 100644
index 00000000000..33f555cb07f
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/ide/IdeSymbolsAnalysisPlugin.kt
@@ -0,0 +1,11 @@
+package org.jetbrains.dokka.analysis.kotlin.symbols.ide
+
+import org.jetbrains.dokka.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
+import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement
+
+class IdeSymbolsAnalysisPlugin : DokkaPlugin() {
+
+    @OptIn(DokkaPluginApiPreview::class)
+    override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
+}
diff --git a/analysis/kotlin-analysis-symbols/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/analysis/kotlin-analysis-symbols/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000000..592455784a5
--- /dev/null
+++ b/analysis/kotlin-analysis-symbols/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.analysis.kotlin.symbols.ide.IdeSymbolsAnalysisPlugin
diff --git a/analysis/markdown/api/markdown.api b/analysis/markdown/api/markdown.api
new file mode 100644
index 00000000000..2419c8e7c44
--- /dev/null
+++ b/analysis/markdown/api/markdown.api
@@ -0,0 +1,40 @@
+public final class org/jetbrains/dokka/analysis/markdown/MarkdownApiKt {
+	public static final fun getMARKDOWN_FILE_NAME ()Ljava/lang/String;
+}
+
+public class org/jetbrains/dokka/analysis/markdown/MarkdownParser : org/jetbrains/dokka/analysis/markdown/Parser {
+	public static final field Companion Lorg/jetbrains/dokka/analysis/markdown/MarkdownParser$Companion;
+	public fun  (Lkotlin/jvm/functions/Function1;Ljava/lang/String;)V
+	public fun parseStringToDocNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocTag;
+	public fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper;
+	public fun preparse (Ljava/lang/String;)Ljava/lang/String;
+}
+
+public final class org/jetbrains/dokka/analysis/markdown/MarkdownParser$Companion {
+	public final fun fqDeclarationName (Lorg/jetbrains/dokka/links/DRI;)Ljava/lang/String;
+}
+
+public final class org/jetbrains/dokka/analysis/markdown/ParseUtilsKt {
+	public static final fun parseHtmlEncodedWithNormalisedSpaces (Ljava/lang/String;Z)Ljava/util/List;
+}
+
+public abstract class org/jetbrains/dokka/analysis/markdown/Parser {
+	public fun  ()V
+	public fun parse (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
+	public abstract fun parseStringToDocNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocTag;
+	public fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper;
+	public abstract fun preparse (Ljava/lang/String;)Ljava/lang/String;
+}
+
+public final class org/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory {
+	public static final field INSTANCE Lorg/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory;
+	public final fun getInstance (Lorg/intellij/markdown/IElementType;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Z)Ljava/util/List;
+	public static synthetic fun getInstance$default (Lorg/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory;Lorg/intellij/markdown/IElementType;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;ZILjava/lang/Object;)Ljava/util/List;
+}
+
+public final class org/jetbrains/dokka/analysis/markdown/factories/DocTagsFromStringFactory {
+	public static final field INSTANCE Lorg/jetbrains/dokka/analysis/markdown/factories/DocTagsFromStringFactory;
+	public final fun getInstance (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;)Lorg/jetbrains/dokka/model/doc/DocTag;
+	public static synthetic fun getInstance$default (Lorg/jetbrains/dokka/analysis/markdown/factories/DocTagsFromStringFactory;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/doc/DocTag;
+}
+
diff --git a/analysis/markdown/build.gradle.kts b/analysis/markdown/build.gradle.kts
new file mode 100644
index 00000000000..bf4b0384e4e
--- /dev/null
+++ b/analysis/markdown/build.gradle.kts
@@ -0,0 +1,17 @@
+import org.jetbrains.registerDokkaArtifactPublication
+
+plugins {
+    id("org.jetbrains.conventions.kotlin-jvm")
+    id("org.jetbrains.conventions.maven-publish")
+}
+
+dependencies {
+    compileOnly(projects.core)
+
+    implementation(libs.jsoup)
+    implementation(libs.jetbrains.markdown)
+}
+
+registerDokkaArtifactPublication("markdownAnalysis") {
+    artifactId = "markdown-analysis"
+}
diff --git a/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownApi.kt b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownApi.kt
new file mode 100644
index 00000000000..f5b5d6a56ee
--- /dev/null
+++ b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownApi.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.analysis.markdown
+
+import org.intellij.markdown.MarkdownElementTypes
+import org.jetbrains.dokka.InternalDokkaApi
+
+@InternalDokkaApi
+val MARKDOWN_FILE_NAME = MarkdownElementTypes.MARKDOWN_FILE.name
diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownParser.kt
similarity index 79%
rename from plugins/base/src/main/kotlin/parsers/MarkdownParser.kt
rename to analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownParser.kt
index d49e7c7a117..d0b328f0923 100644
--- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt
+++ b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/MarkdownParser.kt
@@ -1,6 +1,5 @@
-package org.jetbrains.dokka.base.parsers
+package org.jetbrains.dokka.analysis.markdown
 
-import com.intellij.psi.PsiElement
 import org.intellij.markdown.MarkdownElementTypes
 import org.intellij.markdown.MarkdownTokenTypes
 import org.intellij.markdown.ast.ASTNode
@@ -11,18 +10,16 @@ import org.intellij.markdown.flavours.gfm.GFMElementTypes
 import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
 import org.intellij.markdown.flavours.gfm.GFMTokenTypes
 import org.intellij.markdown.html.HtmlGenerator
-import org.jetbrains.dokka.base.parsers.factories.DocTagsFromIElementFactory
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.analysis.markdown.factories.DocTagsFromIElementFactory
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.links.PointingToDeclaration
 import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.model.doc.Suppress
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
 import java.net.MalformedURLException
 import java.net.URL
 import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser
 
+@InternalDokkaApi
 open class MarkdownParser(
     private val externalDri: (String) -> DRI?,
     private val kdocLocation: String?,
@@ -501,87 +498,7 @@ open class MarkdownParser(
 
 
     companion object {
-        fun parseFromKDocTag(
-            kDocTag: KDocTag?,
-            externalDri: (String) -> DRI?,
-            kdocLocation: String?,
-            parseWithChildren: Boolean = true
-        ): DocumentationNode {
-            return if (kDocTag == null) {
-                DocumentationNode(emptyList())
-            } else {
-                fun parseStringToDocNode(text: String) =
-                    MarkdownParser(externalDri, kdocLocation).parseStringToDocNode(text)
-
-                fun pointedLink(tag: KDocTag): DRI? = (parseStringToDocNode("[${tag.getSubjectName()}]")).let {
-                    val link = it.children[0].children[0]
-                    if (link is DocumentationLink) link.dri else null
-                }
-
-                val allTags =
-                    listOf(kDocTag) + if (kDocTag.canHaveParent() && parseWithChildren) getAllKDocTags(findParent(kDocTag)) else emptyList()
-                DocumentationNode(
-                    allTags.map {
-                        when (it.knownTag) {
-                            null -> if (it.name == null) Description(parseStringToDocNode(it.getContent())) else CustomTagWrapper(
-                                parseStringToDocNode(it.getContent()),
-                                it.name!!
-                            )
-                            KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent()))
-                            KDocKnownTag.THROWS -> {
-                                val dri = pointedLink(it)
-                                Throws(
-                                    parseStringToDocNode(it.getContent()),
-                                    dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
-                                    dri,
-                                )
-                            }
-                            KDocKnownTag.EXCEPTION -> {
-                                val dri = pointedLink(it)
-                                Throws(
-                                    parseStringToDocNode(it.getContent()),
-                                    dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
-                                    dri
-                                )
-                            }
-                            KDocKnownTag.PARAM -> Param(
-                                parseStringToDocNode(it.getContent()),
-                                it.getSubjectName().orEmpty()
-                            )
-                            KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent()))
-                            KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent()))
-                            KDocKnownTag.SEE -> {
-                                val dri = pointedLink(it)
-                                See(
-                                    parseStringToDocNode(it.getContent()),
-                                    dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
-                                    dri,
-                                )
-                            }
-                            KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent()))
-                            KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent()))
-                            KDocKnownTag.PROPERTY -> Property(
-                                parseStringToDocNode(it.getContent()),
-                                it.getSubjectName().orEmpty()
-                            )
-                            KDocKnownTag.SAMPLE -> Sample(
-                                parseStringToDocNode(it.getContent()),
-                                it.getSubjectName().orEmpty()
-                            )
-                            KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent()))
-                        }
-                    }
-                )
-            }
-        }
-
-        //Horrible hack but since link resolution is passed as a function i am not able to resolve them otherwise
-        @kotlin.Suppress("DeprecatedCallableAddReplaceWith")
-        @Deprecated("This function makes wrong assumptions and is missing a lot of corner cases related to generics, " +
-                "parameters and static members. This is not supposed to be public API and will not be supported in the future")
-        fun DRI.fqName(): String? = "$packageName.$classNames".takeIf { packageName != null && classNames != null }
-
-        private fun DRI.fqDeclarationName(): String? {
+        fun DRI.fqDeclarationName(): String? {
             if (this.target !is PointingToDeclaration) {
                 return null
             }
@@ -589,16 +506,6 @@ open class MarkdownParser(
                 .joinToString(separator = ".")
                 .takeIf { it.isNotBlank() }
         }
-
-        private fun findParent(kDoc: PsiElement): PsiElement =
-            if (kDoc.canHaveParent()) findParent(kDoc.parent) else kDoc
-
-        private fun PsiElement.canHaveParent(): Boolean = this is KDocSection && knownTag != KDocKnownTag.PROPERTY
-
-        private fun getAllKDocTags(kDocImpl: PsiElement): List =
-            kDocImpl.children.filterIsInstance().filterNot { it is KDocSection } + kDocImpl.children.flatMap {
-                getAllKDocTags(it)
-            }
     }
 }
 
diff --git a/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/ParseUtils.kt b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/ParseUtils.kt
new file mode 100644
index 00000000000..1de87d56daf
--- /dev/null
+++ b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/ParseUtils.kt
@@ -0,0 +1,39 @@
+package org.jetbrains.dokka.analysis.markdown
+
+import org.intellij.markdown.lexer.Compat
+import org.intellij.markdown.lexer.Compat.forEachCodePoint
+import org.jetbrains.dokka.InternalDokkaApi
+import org.jetbrains.dokka.model.doc.DocTag
+import org.jetbrains.dokka.model.doc.Text
+import org.jsoup.internal.StringUtil
+import org.jsoup.nodes.Entities
+
+@InternalDokkaApi
+fun String.parseHtmlEncodedWithNormalisedSpaces(
+    renderWhiteCharactersAsSpaces: Boolean
+): List {
+    val accum = StringBuilder()
+    val tags = mutableListOf()
+    var lastWasWhite = false
+
+    forEachCodePoint { c ->
+        if (renderWhiteCharactersAsSpaces && StringUtil.isWhitespace(c)) {
+            if (!lastWasWhite) {
+                accum.append(' ')
+                lastWasWhite = true
+            }
+        } else if (Compat.codePointToString(c).let { it != Entities.escape(it) }) {
+            accum.toString().takeIf { it.isNotBlank() }?.let { tags.add(Text(it)) }
+            accum.delete(0, accum.length)
+
+            accum.appendCodePoint(c)
+            tags.add(Text(accum.toString(), params = DocTag.contentTypeParam("html")))
+            accum.delete(0, accum.length)
+        } else if (!StringUtil.isInvisibleChar(c)) {
+            accum.appendCodePoint(c)
+            lastWasWhite = false
+        }
+    }
+    accum.toString().takeIf { it.isNotBlank() }?.let { tags.add(Text(it)) }
+    return tags
+}
diff --git a/plugins/base/src/main/kotlin/parsers/Parser.kt b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/Parser.kt
similarity index 95%
rename from plugins/base/src/main/kotlin/parsers/Parser.kt
rename to analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/Parser.kt
index af07ec53217..23290383e7c 100644
--- a/plugins/base/src/main/kotlin/parsers/Parser.kt
+++ b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/Parser.kt
@@ -1,19 +1,19 @@
-package org.jetbrains.dokka.base.parsers
+package org.jetbrains.dokka.analysis.markdown
 
+import org.jetbrains.dokka.InternalDokkaApi
 import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.model.doc.Deprecated
-import org.jetbrains.dokka.model.doc.Suppress
 
+@InternalDokkaApi
 abstract class Parser {
 
     abstract fun parseStringToDocNode(extractedString: String): DocTag
 
-    abstract fun preparse(text: String): String
+    protected abstract fun preparse(text: String): String
 
     open fun parse(text: String): DocumentationNode =
         DocumentationNode(extractTagsToListOfPairs(preparse(text)).map { (tag, content) -> parseTagWithBody(tag, content) })
 
-    open fun parseTagWithBody(tagName: String, content: String): TagWrapper =
+    protected open fun parseTagWithBody(tagName: String, content: String): TagWrapper =
         when (tagName) {
             "description" -> Description(parseStringToDocNode(content))
             "author" -> Author(parseStringToDocNode(content))
diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory.kt
similarity index 76%
rename from plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt
rename to analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory.kt
index fed3f7eb2ac..8e6455b25e7 100644
--- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt
+++ b/analysis/markdown/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/factories/DocTagsFromIElementFactory.kt
@@ -1,16 +1,18 @@
-package org.jetbrains.dokka.base.parsers.factories
+package org.jetbrains.dokka.analysis.markdown.factories
 
-import org.jetbrains.dokka.model.doc.*
 import org.intellij.markdown.IElementType
 import org.intellij.markdown.MarkdownElementTypes
 import org.intellij.markdown.MarkdownTokenTypes
 import org.intellij.markdown.flavours.gfm.GFMElementTypes
 import org.intellij.markdown.flavours.gfm.GFMTokenTypes
-import org.jetbrains.dokka.base.translators.parseWithNormalisedSpaces
+import org.jetbrains.dokka.analysis.markdown.MARKDOWN_FILE_NAME
+import org.jetbrains.dokka.analysis.markdown.parseHtmlEncodedWithNormalisedSpaces
 import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.doc.*
 import org.jetbrains.dokka.model.doc.DocTag.Companion.contentTypeParam
+import org.jsoup.Jsoup
 
-object DocTagsFromIElementFactory {
+internal object DocTagsFromIElementFactory {
 
     @Suppress("IMPLICIT_CAST_TO_ANY")
     fun getInstance(type: IElementType, children: List = emptyList(), params: Map = emptyMap(), body: String? = null, dri: DRI? = null, keepFormatting: Boolean = false) =
@@ -52,7 +54,7 @@ object DocTagsFromIElementFactory {
             GFMElementTypes.HEADER                      -> Th(children, params)
             GFMElementTypes.ROW                         -> Tr(children, params)
             GFMTokenTypes.CELL                          -> Td(children, params)
-            MarkdownElementTypes.MARKDOWN_FILE          -> CustomDocTag(children, params, MarkdownElementTypes.MARKDOWN_FILE.name)
+            MarkdownElementTypes.MARKDOWN_FILE          -> CustomDocTag(children, params, MARKDOWN_FILE_NAME)
             MarkdownElementTypes.HTML_BLOCK,
             MarkdownTokenTypes.HTML_TAG,
             MarkdownTokenTypes.HTML_BLOCK_CONTENT       -> Text(body.orEmpty(), params = params + contentTypeParam("html"))
@@ -64,4 +66,21 @@ object DocTagsFromIElementFactory {
                 else -> listOf(it as DocTag)
             }
         }
+
+    /**
+     * Parses string into [Text] doc tags that can have either value of the string or html-encoded value with content-type=html parameter.
+     * Content type is added when dealing with html entries like ` `
+     */
+    private fun String.parseWithNormalisedSpaces(
+        renderWhiteCharactersAsSpaces: Boolean
+    ): List {
+        if (!requiresHtmlEncoding()) {
+            return parseHtmlEncodedWithNormalisedSpaces(renderWhiteCharactersAsSpaces)
+        }
+        // parsing it using jsoup is required to get codePoints, otherwise they are interpreted separately, as chars
+        // But we dont need to do it for java as it is already parsed with jsoup
+        return Jsoup.parseBodyFragment(this).body().wholeText().parseHtmlEncodedWithNormalisedSpaces(renderWhiteCharactersAsSpaces)
+    }
+
+    private fun String.requiresHtmlEncoding(): Boolean = indexOf('&') != -1
 }
diff --git a/build.gradle.kts b/build.gradle.kts
index 689e9215a23..d3b965bd43b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -41,10 +41,6 @@ apiValidation {
         // NAME                    PATH
         "frontend",            // :plugins:base:frontend
 
-        "kotlin-analysis",     // :kotlin-analysis
-        "compiler-dependency", // :kotlin-analysis:compiler-dependency
-        "intellij-dependency", // :kotlin-analysis:intellij-dependency
-
         "integration-tests",   // :integration-tests
         "gradle",              // :integration-tests:gradle
         "cli",                 // :integration-tests:cli
diff --git a/core/api/core.api b/core/api/core.api
index 52a612d5be6..47c268f0a3c 100644
--- a/core/api/core.api
+++ b/core/api/core.api
@@ -1456,6 +1456,7 @@ public final class org/jetbrains/dokka/model/DocumentableKt {
 }
 
 public abstract interface class org/jetbrains/dokka/model/DocumentableSource {
+	public abstract fun getLineNumber ()Ljava/lang/Integer;
 	public abstract fun getPath ()Ljava/lang/String;
 }
 
@@ -1779,6 +1780,24 @@ public final class org/jetbrains/dokka/model/Invariance : org/jetbrains/dokka/mo
 	public fun toString ()Ljava/lang/String;
 }
 
+public final class org/jetbrains/dokka/model/IsAlsoParameter : org/jetbrains/dokka/model/properties/ExtraProperty {
+	public static final field Companion Lorg/jetbrains/dokka/model/IsAlsoParameter$Companion;
+	public fun  (Ljava/util/List;)V
+	public final fun component1 ()Ljava/util/List;
+	public final fun copy (Ljava/util/List;)Lorg/jetbrains/dokka/model/IsAlsoParameter;
+	public static synthetic fun copy$default (Lorg/jetbrains/dokka/model/IsAlsoParameter;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/IsAlsoParameter;
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getInSourceSets ()Ljava/util/List;
+	public fun getKey ()Lorg/jetbrains/dokka/model/properties/ExtraProperty$Key;
+	public fun hashCode ()I
+	public fun toString ()Ljava/lang/String;
+}
+
+public final class org/jetbrains/dokka/model/IsAlsoParameter$Companion : org/jetbrains/dokka/model/properties/ExtraProperty$Key {
+	public synthetic fun mergeStrategyFor (Ljava/lang/Object;Ljava/lang/Object;)Lorg/jetbrains/dokka/model/properties/MergeStrategy;
+	public fun mergeStrategyFor (Lorg/jetbrains/dokka/model/IsAlsoParameter;Lorg/jetbrains/dokka/model/IsAlsoParameter;)Lorg/jetbrains/dokka/model/properties/MergeStrategy;
+}
+
 public final class org/jetbrains/dokka/model/IsVar : org/jetbrains/dokka/model/properties/ExtraProperty, org/jetbrains/dokka/model/properties/ExtraProperty$Key {
 	public static final field INSTANCE Lorg/jetbrains/dokka/model/IsVar;
 	public fun getKey ()Lorg/jetbrains/dokka/model/properties/ExtraProperty$Key;
@@ -4397,6 +4416,7 @@ public abstract class org/jetbrains/dokka/plugability/DokkaPlugin {
 	protected final fun extending (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/dokka/plugability/DokkaPlugin$ExtensionProvider;
 	protected final fun extensionPoint ()Lkotlin/properties/ReadOnlyProperty;
 	public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
+	protected final fun getLogger ()Lorg/jetbrains/dokka/utilities/DokkaLogger;
 	protected abstract fun pluginApiPreviewAcknowledgement ()Lorg/jetbrains/dokka/plugability/PluginApiPreviewAcknowledgement;
 	public final fun setContext (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
 	protected final fun unsafeInstall (Lkotlin/Lazy;)V
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 1afed43d1b5..2a5b668cfa1 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -7,11 +7,8 @@ plugins {
 }
 
 dependencies {
-    api(libs.jetbrains.markdown)
     implementation(kotlin("reflect"))
-
-    implementation(libs.jsoup)
-
+    implementation(libs.kotlinx.coroutines.core)
     implementation(libs.jackson.kotlin)
     implementation(libs.jackson.xml)
     constraints {
@@ -20,8 +17,6 @@ dependencies {
         }
     }
 
-    implementation(libs.kotlinx.coroutines.core)
-
     testImplementation(projects.core.testApi)
     testImplementation(kotlin("test-junit"))
 }
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt
index ddfa0c69eff..8b5196c3372 100644
--- a/core/src/main/kotlin/CoreExtensions.kt
+++ b/core/src/main/kotlin/CoreExtensions.kt
@@ -1,7 +1,7 @@
 package org.jetbrains.dokka
 
 import org.jetbrains.dokka.generation.Generation
-import org.jetbrains.dokka.plugability.*
+import org.jetbrains.dokka.plugability.ExtensionPoint
 import org.jetbrains.dokka.renderers.PostAction
 import org.jetbrains.dokka.renderers.Renderer
 import org.jetbrains.dokka.transformers.documentation.DocumentableMerger
@@ -28,4 +28,4 @@ object CoreExtensions {
         operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy> =
             lazy { ExtensionPoint(thisRef::class.qualifiedName!!, property.name) }
     }
-}
\ No newline at end of file
+}
diff --git a/core/src/main/kotlin/DokkaBootstrap.kt b/core/src/main/kotlin/DokkaBootstrap.kt
index f4533d5b344..10a91c5e41a 100644
--- a/core/src/main/kotlin/DokkaBootstrap.kt
+++ b/core/src/main/kotlin/DokkaBootstrap.kt
@@ -1,7 +1,6 @@
 package org.jetbrains.dokka
 
 import java.util.function.BiConsumer
-import kotlin.jvm.Throws
 
 interface DokkaBootstrap {
     @Throws(Throwable::class)
diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt
index adc51cfc73a..52e15ea6b14 100644
--- a/core/src/main/kotlin/model/Documentable.kt
+++ b/core/src/main/kotlin/model/Documentable.kt
@@ -517,6 +517,7 @@ fun  SourceSetDependent?.orEmpty(): SourceSetDependent = this ?: emptyM
 
 interface DocumentableSource {
     val path: String
+    val lineNumber: Int?
 }
 
-data class TypeConstructorWithKind(val typeConstructor: TypeConstructor, val kind: ClassKind)
\ No newline at end of file
+data class TypeConstructorWithKind(val typeConstructor: TypeConstructor, val kind: ClassKind)
diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt
index 9fe8aa1de9b..4e743b0a591 100644
--- a/core/src/main/kotlin/model/documentableProperties.kt
+++ b/core/src/main/kotlin/model/documentableProperties.kt
@@ -49,6 +49,15 @@ object IsVar : ExtraProperty, ExtraProperty.Key {
     override val key: ExtraProperty.Key = this
 }
 
+data class IsAlsoParameter(val inSourceSets: List) : ExtraProperty {
+    companion object : ExtraProperty.Key {
+        override fun mergeStrategyFor(left: IsAlsoParameter, right: IsAlsoParameter): MergeStrategy =
+            MergeStrategy.Replace(IsAlsoParameter(left.inSourceSets + right.inSourceSets))
+    }
+
+    override val key: ExtraProperty.Key = IsAlsoParameter
+}
+
 data class CheckedExceptions(val exceptions: SourceSetDependent>) : ExtraProperty, ExtraProperty.Key {
     companion object : ExtraProperty.Key {
         override fun mergeStrategyFor(left: CheckedExceptions, right: CheckedExceptions) =
diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt
index 54733ac2b34..99fa4b95c45 100644
--- a/core/src/main/kotlin/plugability/DokkaPlugin.kt
+++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule
 import com.fasterxml.jackson.dataformat.xml.XmlMapper
 import com.fasterxml.jackson.module.kotlin.readValue
 import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.utilities.DokkaLogger
 import org.jetbrains.dokka.utilities.parseJson
 import kotlin.properties.ReadOnlyProperty
 import kotlin.reflect.KProperty
@@ -33,6 +34,8 @@ abstract class DokkaPlugin {
     @PublishedApi
     internal var context: DokkaContext? = null
 
+    protected val logger: DokkaLogger get() = context?.logger ?: throw IllegalStateException("No logger found")
+
     /**
      * @see PluginApiPreviewAcknowledgement
      */
diff --git a/core/src/main/kotlin/utilities/Html.kt b/core/src/main/kotlin/utilities/Html.kt
index a1d8ececb67..262dd0a0997 100644
--- a/core/src/main/kotlin/utilities/Html.kt
+++ b/core/src/main/kotlin/utilities/Html.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 import java.net.URLEncoder
 
 
diff --git a/core/src/main/kotlin/utilities/SelfRepresentingSingletonSet.kt b/core/src/main/kotlin/utilities/SelfRepresentingSingletonSet.kt
index c29d1b2afcf..e1b423883da 100644
--- a/core/src/main/kotlin/utilities/SelfRepresentingSingletonSet.kt
+++ b/core/src/main/kotlin/utilities/SelfRepresentingSingletonSet.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 
 @InternalDokkaApi
 interface SelfRepresentingSingletonSet> : Set {
diff --git a/core/src/main/kotlin/utilities/ServiceLocator.kt b/core/src/main/kotlin/utilities/ServiceLocator.kt
index f86960ec407..b5b19057a4d 100644
--- a/core/src/main/kotlin/utilities/ServiceLocator.kt
+++ b/core/src/main/kotlin/utilities/ServiceLocator.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 import java.io.File
 import java.net.URISyntaxException
 import java.net.URL
diff --git a/core/src/main/kotlin/utilities/Uri.kt b/core/src/main/kotlin/utilities/Uri.kt
index 67c81d98b1b..ef8549f7583 100644
--- a/core/src/main/kotlin/utilities/Uri.kt
+++ b/core/src/main/kotlin/utilities/Uri.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 import java.net.URI
 
 @InternalDokkaApi
diff --git a/core/src/main/kotlin/utilities/associateWithNotNull.kt b/core/src/main/kotlin/utilities/associateWithNotNull.kt
index 6c0bf4d83ec..9ff55d2c682 100644
--- a/core/src/main/kotlin/utilities/associateWithNotNull.kt
+++ b/core/src/main/kotlin/utilities/associateWithNotNull.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 
 @InternalDokkaApi
 inline fun  Iterable.associateWithNotNull(valueSelector: (K) -> V?): Map {
diff --git a/core/src/main/kotlin/utilities/cast.kt b/core/src/main/kotlin/utilities/cast.kt
index 784b7e2a9b6..9fe76ef69ca 100644
--- a/core/src/main/kotlin/utilities/cast.kt
+++ b/core/src/main/kotlin/utilities/cast.kt
@@ -1,6 +1,6 @@
 package org.jetbrains.dokka.utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.InternalDokkaApi
 
 @InternalDokkaApi
 inline fun  Any.cast(): T {
diff --git a/core/src/main/kotlin/utilities/parallelCollectionOperations.kt b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
index d24aa7a67bd..cff8d735f35 100644
--- a/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
+++ b/core/src/main/kotlin/utilities/parallelCollectionOperations.kt
@@ -1,7 +1,10 @@
 package org.jetbrains.dokka.utilities
 
-import kotlinx.coroutines.*
-import org.jetbrains.dokka.*
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+import org.jetbrains.dokka.InternalDokkaApi
 
 @InternalDokkaApi
 suspend inline fun  Iterable.parallelMap(crossinline f: suspend (A) -> B): List = coroutineScope {
diff --git a/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt b/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt
index 9ac5fea07c4..d93ea5dfb7c 100644
--- a/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt
+++ b/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt
@@ -1,6 +1,9 @@
 package utilities
 
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.DokkaConfigurationImpl
+import org.jetbrains.dokka.DokkaSourceSetID
+import org.jetbrains.dokka.DokkaSourceSetImpl
+import org.jetbrains.dokka.toCompactJsonString
 import java.io.File
 import kotlin.test.Test
 import kotlin.test.assertEquals
diff --git a/core/src/test/kotlin/utilities/JsonKtTest.kt b/core/src/test/kotlin/utilities/JsonKtTest.kt
index ee78392cea4..301f4f5d79b 100644
--- a/core/src/test/kotlin/utilities/JsonKtTest.kt
+++ b/core/src/test/kotlin/utilities/JsonKtTest.kt
@@ -2,8 +2,8 @@ package utilities
 
 import org.jetbrains.dokka.utilities.serializeAsCompactJson
 import org.jetbrains.dokka.utilities.serializeAsPrettyJson
-import kotlin.test.assertEquals
 import kotlin.test.Test
+import kotlin.test.assertEquals
 
 class JsonTest {
 
diff --git a/core/test-api/api/test-api.api b/core/test-api/api/test-api.api
index 83335672940..496162b232e 100644
--- a/core/test-api/api/test-api.api
+++ b/core/test-api/api/test-api.api
@@ -191,7 +191,6 @@ public final class testApi/testRunner/TestDokkaConfigurationBuilderKt {
 	public static synthetic fun dModule$default (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/DModule;
 	public static final fun dPackage (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;)Lorg/jetbrains/dokka/model/DPackage;
 	public static synthetic fun dPackage$default (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/Map;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/DPackage;
-	public static final fun documentationNode ([Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
 	public static final fun dokkaConfiguration (Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/dokka/DokkaConfigurationImpl;
 	public static final fun getDefaultSourceSet ()Lorg/jetbrains/dokka/DokkaSourceSetImpl;
 	public static final fun sourceSet (Ljava/lang/String;)Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;
diff --git a/core/test-api/build.gradle.kts b/core/test-api/build.gradle.kts
index 1eb8f00cd62..6b4b4d17366 100644
--- a/core/test-api/build.gradle.kts
+++ b/core/test-api/build.gradle.kts
@@ -7,7 +7,7 @@ plugins {
 
 dependencies {
     api(projects.core)
-    implementation(projects.kotlinAnalysis)
+
     implementation("junit:junit:4.13.2") // TODO: remove dependency to junit
     implementation(kotlin("reflect"))
 }
diff --git a/core/test-api/src/main/kotlin/testApi/logger/TestLogger.kt b/core/test-api/src/main/kotlin/testApi/logger/TestLogger.kt
index e70200a7bc3..1e3017355a7 100644
--- a/core/test-api/src/main/kotlin/testApi/logger/TestLogger.kt
+++ b/core/test-api/src/main/kotlin/testApi/logger/TestLogger.kt
@@ -1,7 +1,7 @@
 package org.jetbrains.dokka.testApi.logger
 
 import org.jetbrains.dokka.utilities.DokkaLogger
-import java.util.Collections
+import java.util.*
 
 /*
  * Even in tests it be used in a concurrent environment, so needs to be thread safe
diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt
index 50ab3bad9dc..c63f5b2ec3c 100644
--- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt
+++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt
@@ -1,6 +1,5 @@
 package testApi.testRunner
 
-import org.intellij.markdown.MarkdownElementTypes
 import org.jetbrains.dokka.*
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.*
@@ -206,6 +205,5 @@ fun dPackage(
 fun documentationNode(vararg texts: String): DocumentationNode {
     return DocumentationNode(
         texts.toList()
-            .map { Description(CustomDocTag(listOf(Text(it)), name = MarkdownElementTypes.MARKDOWN_FILE.name)) })
+            .map { Description(CustomDocTag(listOf(Text(it)), name = "MARKDOWN_FILE")) })
 }
-
diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt
index 31443b2d9f3..cfb809eacc9 100644
--- a/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt
+++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt
@@ -1,7 +1,8 @@
 package org.jetbrains.dokka.testApi.testRunner
 
-import com.intellij.openapi.application.PathManager
-import org.jetbrains.dokka.*
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.DokkaConfigurationImpl
+import org.jetbrains.dokka.ExternalDocumentationLinkImpl
 import org.jetbrains.dokka.model.DModule
 import org.jetbrains.dokka.pages.RootPageNode
 import org.jetbrains.dokka.plugability.DokkaContext
@@ -37,7 +38,7 @@ abstract class AbstractTest, D : DokkaTestGe
         cleanupOutput: Boolean = true,
         useOutputLocationFromConfig: Boolean = false,
         pluginOverrides: List = emptyList(),
-        block: T.() -> Unit
+        block: T.() -> Unit,
     ) {
         val testMethods = testBuilder().apply(block).build()
         val configurationToUse =
@@ -65,7 +66,7 @@ abstract class AbstractTest, D : DokkaTestGe
         cleanupOutput: Boolean = true,
         pluginOverrides: List = emptyList(),
         loggerForTest: DokkaLogger = logger,
-        block: T.() -> Unit
+        block: T.() -> Unit,
     ) {
         val testMethods = testBuilder().apply(block).build()
         val testDirPath = getTempDir(cleanupOutput).root.toPath().toAbsolutePath()
@@ -133,7 +134,7 @@ abstract class AbstractTest, D : DokkaTestGe
 
     private fun Map.materializeFiles(
         root: Path = Paths.get("."),
-        charset: Charset = Charset.forName("utf-8")
+        charset: Charset = Charset.forName("utf-8"),
     ) = this.map { (path, content) ->
         val file = root.resolve(path)
         Files.createDirectories(file.parent)
@@ -160,11 +161,17 @@ abstract class AbstractTest, D : DokkaTestGe
 
 
     protected val jvmStdlibPath: String? by lazy {
-        PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class")
+        ClassLoader.getSystemResource("kotlin/jvm/Strictfp.class")
+            ?.file
+            ?.replace("file:", "")
+            ?.replaceAfter(".jar", "")
     }
 
     protected val jsStdlibPath: String? by lazy {
-        PathManager.getResourceRoot(Any::class.java, "/kotlin/jquery")
+        ClassLoader.getSystemResource("kotlin/jquery")
+            ?.file
+            ?.replace("file:", "")
+            ?.replaceAfter(".jar", "")
     }
 
     protected val commonStdlibPath: String? by lazy {
@@ -195,7 +202,7 @@ open class CoreTestMethods(
     open val documentablesTransformationStage: (DModule) -> Unit,
     open val pagesGenerationStage: (RootPageNode) -> Unit,
     open val pagesTransformationStage: (RootPageNode) -> Unit,
-    open val renderingStage: (RootPageNode, DokkaContext) -> Unit
+    open val renderingStage: (RootPageNode, DokkaContext) -> Unit,
 ) : TestMethods
 
 abstract class TestBuilder {
@@ -206,7 +213,7 @@ abstract class DokkaTestGenerator(
     protected val configuration: DokkaConfiguration,
     protected val logger: DokkaLogger,
     protected val testMethods: T,
-    protected val additionalPlugins: List = emptyList()
+    protected val additionalPlugins: List = emptyList(),
 ) {
     abstract fun generate()
 }
diff --git a/integration-tests/cli/build.gradle.kts b/integration-tests/cli/build.gradle.kts
index 4e498df1406..d89f2f99313 100644
--- a/integration-tests/cli/build.gradle.kts
+++ b/integration-tests/cli/build.gradle.kts
@@ -23,13 +23,17 @@ val basePluginShadow: Configuration by configurations.creating {
 
 dependencies {
     basePluginShadow(projects.plugins.base)
-    basePluginShadow(projects.kotlinAnalysis) // compileOnly in base plugin
+    basePluginShadow(project(path = ":analysis:kotlin-analysis-descriptors", configuration = "shadow"))
 }
 
 val basePluginShadowJar by tasks.register("basePluginShadowJar", ShadowJar::class) {
     configurations = listOf(basePluginShadow)
     archiveFileName.set("fat-base-plugin-$dokka_version.jar")
     archiveClassifier.set("")
+
+    // service files are merged to make sure all Dokka plugins
+    // from the dependencies are loaded, and not just a single one.
+    mergeServiceFiles()
 }
 
 tasks.integrationTest {
diff --git a/kotlin-analysis/build.gradle.kts b/kotlin-analysis/build.gradle.kts
deleted file mode 100644
index a5908b4ec0b..00000000000
--- a/kotlin-analysis/build.gradle.kts
+++ /dev/null
@@ -1,17 +0,0 @@
-import org.jetbrains.registerDokkaArtifactPublication
-
-plugins {
-    id("org.jetbrains.conventions.kotlin-jvm")
-    id("org.jetbrains.conventions.maven-publish")
-    id("com.github.johnrengelman.shadow")
-}
-
-dependencies {
-    compileOnly(projects.core)
-    api(project("intellij-dependency", configuration = "shadow"))
-    api(project("compiler-dependency", configuration = "shadow"))
-}
-
-registerDokkaArtifactPublication("dokkaAnalysis") {
-    artifactId = "dokka-analysis"
-}
diff --git a/kotlin-analysis/compiler-dependency/build.gradle.kts b/kotlin-analysis/compiler-dependency/build.gradle.kts
deleted file mode 100644
index 5d0a01e09f7..00000000000
--- a/kotlin-analysis/compiler-dependency/build.gradle.kts
+++ /dev/null
@@ -1,26 +0,0 @@
-import org.jetbrains.DokkaPublicationBuilder.Component.Shadow
-import org.jetbrains.registerDokkaArtifactPublication
-
-plugins {
-    id("org.jetbrains.conventions.kotlin-jvm")
-    id("org.jetbrains.conventions.maven-publish")
-    id("com.github.johnrengelman.shadow")
-}
-
-dependencies {
-    api(libs.kotlin.compiler)
-}
-
-tasks {
-    shadowJar {
-        val dokka_version: String by project
-        archiveFileName.set("dokka-kotlin-analysis-compiler-$dokka_version.jar")
-        archiveClassifier.set("")
-        exclude("com/intellij/")
-    }
-}
-
-registerDokkaArtifactPublication("kotlinAnalysisCompiler") {
-    artifactId = "kotlin-analysis-compiler"
-    component = Shadow
-}
diff --git a/kotlin-analysis/intellij-dependency/build.gradle.kts b/kotlin-analysis/intellij-dependency/build.gradle.kts
deleted file mode 100644
index af0999027c1..00000000000
--- a/kotlin-analysis/intellij-dependency/build.gradle.kts
+++ /dev/null
@@ -1,75 +0,0 @@
-import org.jetbrains.DokkaPublicationBuilder.Component.Shadow
-import org.jetbrains.registerDokkaArtifactPublication
-
-plugins {
-    id("org.jetbrains.conventions.kotlin-jvm")
-    id("org.jetbrains.conventions.maven-publish")
-    id("com.github.johnrengelman.shadow")
-}
-
-repositories {
-    // Override the shared repositories defined in the root settings.gradle.kts
-    // These repositories are very specific and are not needed in other projects
-    mavenCentral()
-    maven("https://www.jetbrains.com/intellij-repository/snapshots") {
-        mavenContent { snapshotsOnly() }
-    }
-    maven("https://www.jetbrains.com/intellij-repository/releases")
-    maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide")
-    maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies")
-    maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
-    maven("https://www.myget.org/F/rd-snapshots/maven/")
-}
-
-val intellijCore: Configuration by configurations.creating
-
-fun intellijCoreAnalysis() = zipTree(intellijCore.singleFile).matching {
-    include("intellij-core.jar")
-}
-
-val jpsStandalone: Configuration by configurations.creating
-
-fun jpsModel() = zipTree(jpsStandalone.singleFile).matching {
-    include("jps-model.jar")
-    include("aalto-xml-*.jar")
-}
-
-dependencies {
-    api(libs.kotlin.idePlugin.common)
-    api(libs.kotlin.idePlugin.idea) {
-        isTransitive = false
-    }
-    api(libs.kotlin.idePlugin.core)
-    api(libs.kotlin.idePlugin.native)
-
-    @Suppress("UnstableApiUsage")
-    intellijCore(libs.jetbrains.intellij.core)
-    implementation(intellijCoreAnalysis())
-
-    @Suppress("UnstableApiUsage")
-    jpsStandalone(libs.jetbrains.intellij.jpsStandalone)
-    implementation(jpsModel())
-}
-
-tasks {
-    shadowJar {
-        val dokka_version: String by project
-        archiveFileName.set("dokka-kotlin-analysis-intellij-$dokka_version.jar")
-        archiveClassifier.set("")
-
-        exclude("colorScheme/**")
-        exclude("fileTemplates/**")
-        exclude("inspectionDescriptions/**")
-        exclude("intentionDescriptions/**")
-        exclude("tips/**")
-        exclude("messages/**")
-        exclude("src/**")
-        exclude("**/*.kotlin_metadata")
-        exclude("**/*.kotlin_builtins")
-    }
-}
-
-registerDokkaArtifactPublication("kotlinAnalysisIntelliJ") {
-    artifactId = "kotlin-analysis-intellij"
-    component = Shadow
-}
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AbsolutePathString.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AbsolutePathString.kt
deleted file mode 100644
index 7c8b6840e2e..00000000000
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/AbsolutePathString.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package org.jetbrains.dokka.analysis
-
-internal typealias AbsolutePathString = String
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt
deleted file mode 100644
index 0c55fed43e0..00000000000
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/Documentable.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.jetbrains.dokka.analysis
-
-import com.intellij.psi.PsiNamedElement
-import org.jetbrains.dokka.model.DocumentableSource
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.load.kotlin.toSourceElement
-
-class DescriptorDocumentableSource(val descriptor: DeclarationDescriptor) : DocumentableSource {
-    override val path = descriptor.toSourceElement.containingFile.toString()
-}
-
-class PsiDocumentableSource(val psi: PsiNamedElement) : DocumentableSource {
-    override val path = psi.containingFile.virtualFile.path
-}
diff --git a/plugins/all-modules-page/build.gradle.kts b/plugins/all-modules-page/build.gradle.kts
index d0778dc5215..f0c28fa80a6 100644
--- a/plugins/all-modules-page/build.gradle.kts
+++ b/plugins/all-modules-page/build.gradle.kts
@@ -11,27 +11,20 @@ registerDokkaArtifactPublication("dokkaAllModulesPage") {
 
 dependencies {
     compileOnly(projects.core)
-    implementation(kotlin("reflect"))
+    compileOnly(projects.analysis.kotlinAnalysisApi)
 
-    compileOnly(projects.kotlinAnalysis)
     implementation(projects.plugins.base)
     implementation(projects.plugins.templating)
+
+    implementation(projects.analysis.markdown)
+
+    implementation(libs.kotlinx.html)
+
     testImplementation(projects.plugins.base)
     testImplementation(projects.plugins.base.baseTestUtils)
     testImplementation(projects.plugins.gfm)
     testImplementation(projects.plugins.gfm.gfmTemplateProcessing)
     testImplementation(projects.core.contentMatcherTestUtils)
-
-    implementation(libs.kotlinx.coroutines.core)
-    implementation(libs.jackson.kotlin)
-    constraints {
-        implementation(libs.jackson.databind) {
-            because("CVE-2022-42003")
-        }
-    }
-    implementation(libs.kotlinx.html)
-    implementation(libs.jsoup)
-
     testImplementation(projects.core.testApi)
     testImplementation(platform(libs.junit.bom))
     testImplementation(libs.junit.jupiter)
diff --git a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt
index 2901f361f5b..161efd2e68c 100644
--- a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt
+++ b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt
@@ -2,12 +2,8 @@ package org.jetbrains.dokka.allModulesPage
 
 import org.jetbrains.dokka.DokkaConfiguration.DokkaModuleDescription
 import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.analysis.markdown.MarkdownParser
 import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.base.parsers.MarkdownParser
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments
 import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
 import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
 import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
@@ -22,6 +18,7 @@ import org.jetbrains.dokka.plugability.plugin
 import org.jetbrains.dokka.plugability.querySingle
 import org.jetbrains.dokka.transformers.pages.PageCreator
 import org.jetbrains.dokka.utilities.DokkaLogger
+import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin
 import java.io.File
 
 class MultimodulePageCreator(
@@ -31,6 +28,7 @@ class MultimodulePageCreator(
 
     private val commentsConverter by lazy { context.plugin().querySingle { commentsToContentConverter } }
     private val signatureProvider by lazy { context.plugin().querySingle { signatureProvider } }
+    private val moduleDocumentationReader by lazy { context.plugin().querySingle { moduleAndPackageDocumentationReader } }
 
     override fun invoke(creationContext: AllModulesPageGeneration.DefaultAllModulesContext): RootPageNode {
         val modules = context.configuration.modules
@@ -88,15 +86,7 @@ class MultimodulePageCreator(
         files.map { MarkdownParser({ null }, it.absolutePath).parse(it.readText()) }
 
     private fun getDisplayedModuleDocumentation(module: DokkaModuleDescription): P? {
-        val parsingContext = ModuleAndPackageDocumentationParsingContext(logger)
-
-        val documentationFragment = module.includes
-            .flatMap { include -> parseModuleAndPackageDocumentationFragments(include) }
-            .firstOrNull { fragment -> fragment.classifier == Module && fragment.name == module.name }
-            ?: return null
-
-        val moduleDocumentation = parseModuleAndPackageDocumentation(parsingContext, documentationFragment)
-        return moduleDocumentation.documentation.firstParagraph()
+        return moduleDocumentationReader.read(module)?.firstParagraph()
     }
 
     private fun DocumentationNode.firstParagraph(): P? =
diff --git a/plugins/android-documentation/build.gradle.kts b/plugins/android-documentation/build.gradle.kts
index 5ef734b8ad8..4dfc972ddb8 100644
--- a/plugins/android-documentation/build.gradle.kts
+++ b/plugins/android-documentation/build.gradle.kts
@@ -8,9 +8,10 @@ plugins {
 dependencies {
     compileOnly(projects.core)
 
-    implementation(kotlin("reflect"))
     implementation(projects.plugins.base)
 
+    implementation(kotlin("reflect"))
+
     testImplementation(projects.plugins.base)
     testImplementation(projects.plugins.base.baseTestUtils)
     testImplementation(projects.core.testApi)
diff --git a/plugins/android-documentation/src/test/kotlin/transformers/HideTagDocumentableFilterTest.kt b/plugins/android-documentation/src/test/kotlin/transformers/HideTagDocumentableFilterTest.kt
index 823752012ce..180268e4ba2 100644
--- a/plugins/android-documentation/src/test/kotlin/transformers/HideTagDocumentableFilterTest.kt
+++ b/plugins/android-documentation/src/test/kotlin/transformers/HideTagDocumentableFilterTest.kt
@@ -2,8 +2,8 @@ package transformers
 
 import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
 import org.jetbrains.dokka.model.DClass
-import kotlin.test.assertEquals
 import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
 
 class HideTagDocumentableFilterTest : BaseAbstractTest() {
     private val configuration = dokkaConfiguration {
@@ -68,4 +68,4 @@ class HideTagDocumentableFilterTest : BaseAbstractTest() {
     }
 
 
-}
\ No newline at end of file
+}
diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api
index 7875800efe1..c01b492864f 100644
--- a/plugins/base/api/base.api
+++ b/plugins/base/api/base.api
@@ -6,12 +6,7 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
 	public final fun getCommentsToContentConverter ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
 	public final fun getCustomResourceInstaller ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getCustomTagContentProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
-	public final fun getDefaultExternalClasslikesTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getDefaultExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getDefaultKotlinAnalysis ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getDefaultSamplesTransformer ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getDeprecatedDocumentableFilter ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getDescriptorToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getDocTagToContentConverter ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getDocumentableMerger ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getDocumentableToPageTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
@@ -20,8 +15,6 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
 	public final fun getEmptyModulesFilter ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getEmptyPackagesFilter ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getExtensionsExtractor ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getExternalClasslikesTranslator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
-	public final fun getExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
 	public final fun getExternalLocationProviderFactory ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
 	public final fun getFallbackMerger ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getFileWriter ()Lorg/jetbrains/dokka/plugability/Extension;
@@ -31,7 +24,6 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
 	public final fun getInheritedEntriesVisbilityFilter ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getInheritorsExtractor ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getJavadocLocationProvider ()Lorg/jetbrains/dokka/plugability/Extension;
-	public final fun getKotlinAnalysis ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
 	public final fun getKotlinArrayDocumentableReplacer ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getKotlinSignatureProvider ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getLocationProvider ()Lorg/jetbrains/dokka/plugability/Extension;
@@ -45,7 +37,6 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug
 	public final fun getPageMergerStrategy ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
 	public final fun getPathToRootConsumer ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getPreMergeDocumentableTransformer ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
-	public final fun getPsiToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getReplaceVersionConsumer ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getResolveLinkConsumer ()Lorg/jetbrains/dokka/plugability/Extension;
 	public final fun getRootCreator ()Lorg/jetbrains/dokka/plugability/Extension;
@@ -120,104 +111,6 @@ public final class org/jetbrains/dokka/base/generation/SingleModuleGeneration :
 	public final fun validityCheck (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
 }
 
-public class org/jetbrains/dokka/base/parsers/MarkdownParser : org/jetbrains/dokka/base/parsers/Parser {
-	public static final field Companion Lorg/jetbrains/dokka/base/parsers/MarkdownParser$Companion;
-	public fun  (Lkotlin/jvm/functions/Function1;Ljava/lang/String;)V
-	public fun parseStringToDocNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocTag;
-	public fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper;
-	public fun preparse (Ljava/lang/String;)Ljava/lang/String;
-}
-
-public final class org/jetbrains/dokka/base/parsers/MarkdownParser$Companion {
-	public final fun fqName (Lorg/jetbrains/dokka/links/DRI;)Ljava/lang/String;
-	public final fun parseFromKDocTag (Lorg/jetbrains/kotlin/kdoc/psi/impl/KDocTag;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Z)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-	public static synthetic fun parseFromKDocTag$default (Lorg/jetbrains/dokka/base/parsers/MarkdownParser$Companion;Lorg/jetbrains/kotlin/kdoc/psi/impl/KDocTag;Lkotlin/jvm/functions/Function1;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-}
-
-public abstract class org/jetbrains/dokka/base/parsers/Parser {
-	public fun  ()V
-	public fun parse (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-	public abstract fun parseStringToDocNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocTag;
-	public fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper;
-	public abstract fun preparse (Ljava/lang/String;)Ljava/lang/String;
-}
-
-public final class org/jetbrains/dokka/base/parsers/factories/DocTagsFromIElementFactory {
-	public static final field INSTANCE Lorg/jetbrains/dokka/base/parsers/factories/DocTagsFromIElementFactory;
-	public final fun getInstance (Lorg/intellij/markdown/IElementType;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;Z)Ljava/util/List;
-	public static synthetic fun getInstance$default (Lorg/jetbrains/dokka/base/parsers/factories/DocTagsFromIElementFactory;Lorg/intellij/markdown/IElementType;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;ZILjava/lang/Object;)Ljava/util/List;
-}
-
-public final class org/jetbrains/dokka/base/parsers/factories/DocTagsFromStringFactory {
-	public static final field INSTANCE Lorg/jetbrains/dokka/base/parsers/factories/DocTagsFromStringFactory;
-	public final fun getInstance (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;)Lorg/jetbrains/dokka/model/doc/DocTag;
-	public static synthetic fun getInstance$default (Lorg/jetbrains/dokka/base/parsers/factories/DocTagsFromStringFactory;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Lorg/jetbrains/dokka/links/DRI;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/doc/DocTag;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation {
-	public fun  (Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Lorg/jetbrains/dokka/model/doc/DocumentationNode;)V
-	public final fun component1 ()Ljava/lang/String;
-	public final fun component2 ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public final fun component3 ()Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-	public final fun copy (Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Lorg/jetbrains/dokka/model/doc/DocumentationNode;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation;
-	public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation;Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Lorg/jetbrains/dokka/model/doc/DocumentationNode;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation;
-	public fun equals (Ljava/lang/Object;)Z
-	public final fun getClassifier ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public final fun getDocumentation ()Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-	public final fun getName ()Ljava/lang/String;
-	public fun hashCode ()I
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier : java/lang/Enum {
-	public static final field Module Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public static final field Package Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public static fun values ()[Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment {
-	public fun  (Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;)V
-	public final fun component1 ()Ljava/lang/String;
-	public final fun component2 ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public final fun component3 ()Ljava/lang/String;
-	public final fun component4 ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;
-	public final fun copy (Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment;
-	public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment;Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;Ljava/lang/String;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment;
-	public fun equals (Ljava/lang/Object;)Z
-	public final fun getClassifier ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation$Classifier;
-	public final fun getDocumentation ()Ljava/lang/String;
-	public final fun getName ()Ljava/lang/String;
-	public final fun getSource ()Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;
-	public fun hashCode ()I
-	public fun toString ()Ljava/lang/String;
-}
-
-public abstract interface class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext {
-	public abstract fun markdownParserFor (Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment;Ljava/lang/String;)Lorg/jetbrains/dokka/base/parsers/MarkdownParser;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContextKt {
-	public static final fun ModuleAndPackageDocumentationParsingContext (Lorg/jetbrains/dokka/utilities/DokkaLogger;Lorg/jetbrains/dokka/analysis/DokkaResolutionFacade;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext;
-	public static synthetic fun ModuleAndPackageDocumentationParsingContext$default (Lorg/jetbrains/dokka/utilities/DokkaLogger;Lorg/jetbrains/dokka/analysis/DokkaResolutionFacade;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext;
-}
-
-public abstract class org/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource {
-	public fun  ()V
-	public abstract fun getDocumentation ()Ljava/lang/String;
-	public abstract fun getSourceDescription ()Ljava/lang/String;
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ParseModuleAndPackageDocumentationFragmentsKt {
-	public static final fun parseModuleAndPackageDocumentationFragments (Ljava/io/File;)Ljava/util/List;
-	public static final fun parseModuleAndPackageDocumentationFragments (Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource;)Ljava/util/List;
-}
-
-public final class org/jetbrains/dokka/base/parsers/moduleAndPackage/ParseModuleAndPackageDocumentationKt {
-	public static final fun parseModuleAndPackageDocumentation (Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext;Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment;)Lorg/jetbrains/dokka/base/parsers/moduleAndPackage/ModuleAndPackageDocumentation;
-}
-
 public final class org/jetbrains/dokka/base/renderers/ContentTypeCheckingKt {
 	public static final fun getURIExtension (Ljava/lang/String;)Ljava/lang/String;
 	public static final fun isImage (Ljava/lang/String;)Z
@@ -391,7 +284,7 @@ public final class org/jetbrains/dokka/base/renderers/html/HtmlRendererKt {
 }
 
 public abstract class org/jetbrains/dokka/base/renderers/html/NavigationDataProvider {
-	public fun  ()V
+	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
 	public fun navigableChildren (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;
 	public fun visit (Lorg/jetbrains/dokka/pages/ContentPage;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNode;
 }
@@ -1275,11 +1168,6 @@ public final class org/jetbrains/dokka/base/transformers/documentables/UtilsKt {
 	public static final fun isException (Lorg/jetbrains/dokka/model/properties/WithExtraProperties;)Z
 }
 
-public final class org/jetbrains/dokka/base/transformers/documentables/utils/FullClassHierarchyBuilder {
-	public fun  ()V
-	public final fun invoke (Lorg/jetbrains/dokka/model/DModule;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-}
-
 public final class org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer : org/jetbrains/dokka/transformers/documentation/DocumentableTransformer {
 	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
 	public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
@@ -1331,21 +1219,6 @@ public final class org/jetbrains/dokka/base/transformers/pages/merger/SourceSetM
 	public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode;
 }
 
-public final class org/jetbrains/dokka/base/transformers/pages/samples/DefaultSamplesTransformer : org/jetbrains/dokka/base/transformers/pages/samples/SamplesTransformer {
-	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
-	public fun processBody (Lcom/intellij/psi/PsiElement;)Ljava/lang/String;
-	public fun processImports (Lcom/intellij/psi/PsiElement;)Ljava/lang/String;
-}
-
-public abstract class org/jetbrains/dokka/base/transformers/pages/samples/SamplesTransformer : org/jetbrains/dokka/transformers/pages/PageTransformer {
-	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
-	protected fun createSampleBody (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-	public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
-	public final fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode;
-	public abstract fun processBody (Lcom/intellij/psi/PsiElement;)Ljava/lang/String;
-	public abstract fun processImports (Lcom/intellij/psi/PsiElement;)Ljava/lang/String;
-}
-
 public final class org/jetbrains/dokka/base/transformers/pages/sourcelinks/SourceLink {
 	public fun  (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)V
 	public fun  (Lorg/jetbrains/dokka/DokkaConfiguration$SourceLinkDefinition;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)V
@@ -1388,43 +1261,6 @@ public final class org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinT
 	public fun isApplicable (Lorg/jetbrains/dokka/model/doc/CustomTagWrapper;)Z
 }
 
-public final class org/jetbrains/dokka/base/translators/descriptors/DRIWithPlatformInfo {
-	public fun  (Lorg/jetbrains/dokka/links/DRI;Ljava/util/Map;)V
-	public final fun component1 ()Lorg/jetbrains/dokka/links/DRI;
-	public final fun component2 ()Ljava/util/Map;
-	public final fun copy (Lorg/jetbrains/dokka/links/DRI;Ljava/util/Map;)Lorg/jetbrains/dokka/base/translators/descriptors/DRIWithPlatformInfo;
-	public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/translators/descriptors/DRIWithPlatformInfo;Lorg/jetbrains/dokka/links/DRI;Ljava/util/Map;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/translators/descriptors/DRIWithPlatformInfo;
-	public fun equals (Ljava/lang/Object;)Z
-	public final fun getActual ()Ljava/util/Map;
-	public final fun getDri ()Lorg/jetbrains/dokka/links/DRI;
-	public fun hashCode ()I
-	public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/dokka/base/translators/descriptors/DefaultDescriptorToDocumentableTranslator : org/jetbrains/dokka/base/translators/descriptors/ExternalClasslikesTranslator, org/jetbrains/dokka/transformers/sources/AsyncSourceToDocumentableTranslator {
-	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
-	public fun invoke (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;)Lorg/jetbrains/dokka/model/DModule;
-	public fun invokeSuspending (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-	public fun translateClassDescriptor (Lorg/jetbrains/kotlin/descriptors/ClassDescriptor;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
-}
-
-public final class org/jetbrains/dokka/base/translators/descriptors/DefaultDescriptorToDocumentableTranslatorKt {
-	public static final fun withEmptyInfo (Lorg/jetbrains/dokka/links/DRI;)Lorg/jetbrains/dokka/base/translators/descriptors/DRIWithPlatformInfo;
-}
-
-public final class org/jetbrains/dokka/base/translators/descriptors/DefaultExternalDocumentablesProvider : org/jetbrains/dokka/base/translators/descriptors/ExternalDocumentablesProvider {
-	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
-	public fun findClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
-}
-
-public abstract interface class org/jetbrains/dokka/base/translators/descriptors/ExternalClasslikesTranslator {
-	public abstract fun translateClassDescriptor (Lorg/jetbrains/kotlin/descriptors/ClassDescriptor;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
-}
-
-public abstract interface class org/jetbrains/dokka/base/translators/descriptors/ExternalDocumentablesProvider {
-	public abstract fun findClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike;
-}
-
 public final class org/jetbrains/dokka/base/translators/documentables/BriefFromContentNodesKt {
 	public static final fun firstParagraphBrief (Lorg/jetbrains/dokka/model/doc/DocTag;)Lorg/jetbrains/dokka/model/doc/DocTag;
 	public static final fun firstSentenceBriefFromContentNodes (Ljava/util/List;)Ljava/util/List;
@@ -1440,8 +1276,8 @@ public final class org/jetbrains/dokka/base/translators/documentables/DefaultDoc
 }
 
 public class org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator {
-	public fun  (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;)V
-	public synthetic fun  (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public fun  (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableAnalyzer;)V
+	public synthetic fun  (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableAnalyzer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	protected fun contentForBrief (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Lorg/jetbrains/dokka/model/Documentable;)V
 	protected fun contentForClasslikesAndEntries (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentGroup;
 	protected fun contentForConstructors (Ljava/util/List;Ljava/util/Set;Ljava/util/Set;)Lorg/jetbrains/dokka/pages/ContentGroup;
@@ -1461,6 +1297,7 @@ public class org/jetbrains/dokka/base/translators/documentables/DefaultPageCreat
 	public static synthetic fun divergentBlock$default (Lorg/jetbrains/dokka/base/translators/documentables/DefaultPageCreator;Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$DocumentableContentBuilder;Ljava/lang/String;Ljava/util/Collection;Lorg/jetbrains/dokka/pages/ContentKind;Lorg/jetbrains/dokka/model/properties/PropertyContainer;ILjava/lang/Object;)V
 	protected fun getContentBuilder ()Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder;
 	public final fun getCustomTagContentProviders ()Ljava/util/List;
+	public final fun getDocumentableAnalyzer ()Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableAnalyzer;
 	public final fun getLogger ()Lorg/jetbrains/dokka/utilities/DokkaLogger;
 	protected final fun getMergeImplicitExpectActualDeclarations ()Z
 	protected final fun getSeparateInheritedMembers ()Z
@@ -1621,27 +1458,3 @@ public class org/jetbrains/dokka/base/translators/documentables/PageContentBuild
 	public static synthetic fun row$default (Lorg/jetbrains/dokka/base/translators/documentables/PageContentBuilder$TableBuilder;Ljava/util/Set;Ljava/util/Set;Lorg/jetbrains/dokka/pages/Kind;Ljava/util/Set;Lorg/jetbrains/dokka/model/properties/PropertyContainer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
 }
 
-public final class org/jetbrains/dokka/base/translators/psi/DefaultPsiToDocumentableTranslator : org/jetbrains/dokka/transformers/sources/AsyncSourceToDocumentableTranslator {
-	public fun  (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
-	public fun invoke (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;)Lorg/jetbrains/dokka/model/DModule;
-	public fun invokeSuspending (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/plugability/DokkaContext;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-}
-
-public final class org/jetbrains/dokka/base/translators/psi/DefaultPsiToDocumentableTranslator$DokkaPsiParser {
-	public fun  (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Lorg/jetbrains/dokka/analysis/DokkaResolutionFacade;Lorg/jetbrains/dokka/utilities/DokkaLogger;)V
-	public final fun parsePackage (Ljava/lang/String;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
-}
-
-public abstract interface class org/jetbrains/dokka/base/translators/psi/parsers/JavaDocumentationParser {
-	public abstract fun parseDocumentation (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-}
-
-public final class org/jetbrains/dokka/base/translators/psi/parsers/JavadocParser : org/jetbrains/dokka/base/translators/psi/parsers/JavaDocumentationParser {
-	public static final field Companion Lorg/jetbrains/dokka/base/translators/psi/parsers/JavadocParser$Companion;
-	public fun  (Lorg/jetbrains/dokka/utilities/DokkaLogger;Lorg/jetbrains/dokka/analysis/DokkaResolutionFacade;)V
-	public fun parseDocumentation (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode;
-}
-
-public final class org/jetbrains/dokka/base/translators/psi/parsers/JavadocParser$Companion {
-}
-
diff --git a/plugins/base/base-test-utils/build.gradle.kts b/plugins/base/base-test-utils/build.gradle.kts
index 2645fbc3c2b..d72edb85204 100644
--- a/plugins/base/base-test-utils/build.gradle.kts
+++ b/plugins/base/base-test-utils/build.gradle.kts
@@ -7,11 +7,13 @@ plugins {
 
 dependencies {
     compileOnly(projects.core)
+    compileOnly(projects.plugins.base)
 
+    api(projects.analysis.kotlinAnalysisApi)
+    runtimeOnly(project(path = ":analysis:kotlin-analysis-descriptors", configuration = "shadow"))
 
     implementation(kotlin("reflect"))
 
-    compileOnly(projects.plugins.base)
     implementation(projects.core.testApi)
 
     implementation(libs.jsoup)
diff --git a/plugins/base/base-test-utils/src/main/kotlin/testRunner/baseTestApi.kt b/plugins/base/base-test-utils/src/main/kotlin/testRunner/baseTestApi.kt
index a11ddb84fef..593a487c022 100644
--- a/plugins/base/base-test-utils/src/main/kotlin/testRunner/baseTestApi.kt
+++ b/plugins/base/base-test-utils/src/main/kotlin/testRunner/baseTestApi.kt
@@ -9,7 +9,10 @@ import org.jetbrains.dokka.pages.RootPageNode
 import org.jetbrains.dokka.plugability.DokkaContext
 import org.jetbrains.dokka.plugability.DokkaPlugin
 import org.jetbrains.dokka.testApi.logger.TestLogger
-import org.jetbrains.dokka.testApi.testRunner.*
+import org.jetbrains.dokka.testApi.testRunner.AbstractTest
+import org.jetbrains.dokka.testApi.testRunner.CoreTestMethods
+import org.jetbrains.dokka.testApi.testRunner.DokkaTestGenerator
+import org.jetbrains.dokka.testApi.testRunner.TestBuilder
 import org.jetbrains.dokka.utilities.DokkaConsoleLogger
 import org.jetbrains.dokka.utilities.DokkaLogger
 import org.jetbrains.dokka.utilities.LoggingLevel
diff --git a/plugins/base/build.gradle.kts b/plugins/base/build.gradle.kts
index b6ba2917667..f786c077ea0 100644
--- a/plugins/base/build.gradle.kts
+++ b/plugins/base/build.gradle.kts
@@ -8,14 +8,16 @@ plugins {
 
 dependencies {
     compileOnly(projects.core)
+    compileOnly(projects.analysis.kotlinAnalysisApi)
 
-    implementation(kotlin("reflect"))
+    implementation(projects.analysis.markdown)
 
+    // Other
+    implementation(kotlin("reflect"))
     implementation(libs.kotlinx.coroutines.core)
-
-    compileOnly(projects.kotlinAnalysis)
     implementation(libs.jsoup)
-
+    implementation(libs.freemarker)
+    implementation(libs.kotlinx.html)
     implementation(libs.jackson.kotlin)
     constraints {
         implementation(libs.jackson.databind) {
@@ -23,14 +25,9 @@ dependencies {
         }
     }
 
-    implementation(libs.freemarker)
-
+    // Test only
     testImplementation(projects.plugins.base.baseTestUtils)
     testImplementation(projects.core.contentMatcherTestUtils)
-
-    implementation(libs.kotlinx.html)
-
-    testImplementation(projects.kotlinAnalysis)
     testImplementation(projects.core.testApi)
     testImplementation(platform(libs.junit.bom))
     testImplementation(libs.junit.jupiter)
diff --git a/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx b/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx
index 1d0c8c1093e..d5150dd537c 100644
--- a/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx
+++ b/plugins/base/frontend/src/main/components/search/dokkaFuzzyFilter.tsx
@@ -2,7 +2,7 @@ import Select from '@jetbrains/ring-ui/components/select/select';
 import {Option, OptionWithHighlightComponent, OptionWithSearchResult} from "./types";
 import fuzzyHighlight from '@jetbrains/ring-ui/components/global/fuzzy-highlight.js'
 import React from "react";
-import {SearchResultRow, signatureFromSearchResult} from "./searchResultRow";
+import {SearchResultRow} from "./searchResultRow";
 import _ from "lodash";
 
 const orderRecords = (records: OptionWithSearchResult[], searchPhrase: string): OptionWithSearchResult[] => {
@@ -94,4 +94,4 @@ export class DokkaFuzzyFilterComponent extends Select {
 
         return highlightMatchedPhrases(orderRecords(matchedRecords, filterPhrase))
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/base/frontend/src/main/components/search/search.tsx b/plugins/base/frontend/src/main/components/search/search.tsx
index d4e406bfd7b..045f6365895 100644
--- a/plugins/base/frontend/src/main/components/search/search.tsx
+++ b/plugins/base/frontend/src/main/components/search/search.tsx
@@ -1,12 +1,12 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import React, {useCallback, useEffect, useState} from 'react';
 import List from '@jetbrains/ring-ui/components/list/list';
 import Select from '@jetbrains/ring-ui/components/select/select';
 import '@jetbrains/ring-ui/components/input-size/input-size.css';
 import './search.scss';
 import {CustomAnchorProps, IWindow, Option, Props} from "./types";
-import { DokkaSearchAnchor } from "./dokkaSearchAnchor";
-import { DokkaFuzzyFilterComponent } from "./dokkaFuzzyFilter";
-import { relativizeUrlForRequest } from '../utils/requests';
+import {DokkaSearchAnchor} from "./dokkaSearchAnchor";
+import {DokkaFuzzyFilterComponent} from "./dokkaFuzzyFilter";
+import {relativizeUrlForRequest} from '../utils/requests';
 
 const WithFuzzySearchFilterComponent: React.FC = ({ data }: Props) => {
     const [selected, onSelected] = useState
".toRegex().findAll(text).toList().size - val isInsidePre = openPre > closedPre - val parsed = when (this) { - is PsiInlineDocTag -> convertInlineDocTag(this, state.currentJavadocTag, context) - is PsiDocParamRef -> toDocumentationLinkString() - is PsiDocTagValue, - is LeafPsiElement -> stringifyElementAsText(isInsidePre, state.previousElement) - else -> null - } - val previousElement = if (text.trim() == "") state.previousElement else this - return ParsingResult( - state.copy( - previousElement = previousElement, - closedPreTags = closedPre, - openPreTags = openPre - ), parsed - ) - } - - private fun PsiElement.stringifyElementAsText(keepFormatting: Boolean, previousElement: PsiElement? = null) = if (keepFormatting) { - /* - For values in the
 tag we try to keep formatting, so only the leading space is trimmed,
-            since it is there because it separates this line from the leading asterisk
-             */
-            text.let {
-                if (((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true || (prevSibling as? PsiDocToken)?.isTagName() == true ) && it.firstOrNull() == ' ')
-                    it.drop(1) else it
-            }.let {
-                if ((nextSibling as? PsiDocToken)?.isLeadingAsterisk() == true) it.dropLastWhile { it == ' ' } else it
-            }
-        } else {
-            /*
-            Outside of the 
 we would like to trim everything from the start and end of a line since
-            javadoc doesn't care about it.
-             */
-            text.let {
-                if ((prevSibling as? PsiDocToken)?.isLeadingAsterisk() == true && text.isNotBlank() && previousElement !is PsiInlineDocTag) it?.trimStart() else it
-            }?.let {
-                if ((nextSibling as? PsiDocToken)?.isLeadingAsterisk() == true && text.isNotBlank()) it.trimEnd() else it
-            }?.let {
-                if (shouldHaveSpaceAtTheEnd()) "$it " else it
-            }
-        }
-
-        /**
-         * We would like to know if we need to have a space after a this tag
-         *
-         * The space is required when:
-         *  - tag spans multiple lines, between every line we would need a space
-         *
-         *  We wouldn't like to render a space if:
-         *  - tag is followed by an end of comment
-         *  - after a tag there is another tag (eg. multiple @author tags)
-         *  - they end with an html tag like: Something since then the space will be displayed in the following text
-         *  - next line starts with a 

or

 token
-         */
-        private fun PsiElement.shouldHaveSpaceAtTheEnd(): Boolean {
-            val siblings = siblings(withItself = false).toList().filterNot { it.text.trim() == "" }
-            val nextNotEmptySibling = (siblings.firstOrNull() as? PsiDocToken)
-            val furtherNotEmptySibling =
-                (siblings.drop(1).firstOrNull { it is PsiDocToken && !it.isLeadingAsterisk() } as? PsiDocToken)
-            val lastHtmlTag = text.trim().substringAfterLast("<")
-            val endsWithAnUnclosedTag = lastHtmlTag.endsWith(">") && !lastHtmlTag.startsWith("${label.ifBlank{ defaultLabel().text }}"""
-        }
-
-        private fun convertInlineDocTag(
-            tag: PsiInlineDocTag,
-            javadocTag: JavadocTag?,
-            context: CommentResolutionContext
-        ) =
-            when (tag.name) {
-                "link", "linkplain" -> tag.referenceElement()
-                    ?.toDocumentationLinkString(tag.dataElements.filterIsInstance().joinToString(" ") {
-                        it.stringifyElementAsText(keepFormatting = false).orEmpty()
-                    })
-                "code" -> "${dataElementsAsText(tag)}"
-                "literal" -> "${dataElementsAsText(tag)}"
-                "index" -> "${tag.children.filterIsInstance().joinToString { it.text }}"
-                "inheritDoc" -> inheritDocResolver.resolveFromContext(context)
-                    ?.fold(ParsingResult(javadocTag)) { result, e ->
-                        result + e.stringify(result.newState, context)
-                    }?.parsedLine.orEmpty()
-                else -> tag.text
-            }
-
-        private fun dataElementsAsText(tag: PsiInlineDocTag) =
-            tag.dataElements.joinToString("") {
-                it.stringifyElementAsText(keepFormatting = true).orEmpty()
-            }.htmlEscape()
-
-        private fun createLink(element: Element, children: List): DocTag {
-            return when {
-                element.hasAttr("docref") ->
-                    A(children, params = mapOf("docref" to element.attr("docref")))
-                element.hasAttr("href") ->
-                    A(children, params = mapOf("href" to element.attr("href")))
-                element.hasAttr("data-dri") && driMap.containsKey(element.attr("data-dri")) ->
-                    DocumentationLink(driMap[element.attr("data-dri")]!!, children)
-                else -> Text(body = children.filterIsInstance().joinToString { it.body })
-            }
-        }
-
-        private fun createBlock(element: Element, keepFormatting: Boolean = false): List {
-            val tagName = element.tagName()
-            val children = element.childNodes()
-                .flatMap { convertHtmlNode(it, keepFormatting = keepFormatting || tagName == "pre" || tagName == "code") }
-
-            fun ifChildrenPresent(operation: () -> DocTag): List {
-                return if (children.isNotEmpty()) listOf(operation()) else emptyList()
-            }
-            return when (tagName) {
-                "blockquote" -> ifChildrenPresent { BlockQuote(children) }
-                "p" -> ifChildrenPresent { P(children) }
-                "b" -> ifChildrenPresent { B(children) }
-                "strong" -> ifChildrenPresent { Strong(children) }
-                "index" -> listOf(Index(children))
-                "i" -> ifChildrenPresent { I(children) }
-                "img" -> listOf(
-                    Img(
-                        children,
-                        element.attributes().associate { (if (it.key == "src") "href" else it.key) to it.value })
-                )
-                "em" -> listOf(Em(children))
-                "code" -> ifChildrenPresent { if(keepFormatting) CodeBlock(children) else CodeInline(children) }
-                "pre" -> if(children.size == 1) {
-                    when(children.first()) {
-                        is CodeInline -> listOf(CodeBlock(children.first().children))
-                        is CodeBlock -> listOf(children.first())
-                        else -> listOf(Pre(children))
-                    }
-                } else {
-                    listOf(Pre(children))
-                }
-                "ul" -> ifChildrenPresent { Ul(children) }
-                "ol" -> ifChildrenPresent { Ol(children) }
-                "li" -> listOf(Li(children))
-                "dl" -> ifChildrenPresent { Dl(children) }
-                "dt" -> listOf(Dt(children))
-                "dd" -> listOf(Dd(children))
-                "a" -> listOf(createLink(element, children))
-                "table" -> ifChildrenPresent { Table(children) }
-                "tr" -> ifChildrenPresent { Tr(children) }
-                "td" -> listOf(Td(children))
-                "thead" -> listOf(THead(children))
-                "tbody" -> listOf(TBody(children))
-                "tfoot" -> listOf(TFoot(children))
-                "caption" -> ifChildrenPresent { Caption(children) }
-                "inheritdoc" -> {
-                    val id = UUID.fromString(element.attr("id"))
-                    val section = inheritDocSections[id]
-                    val parsed = section?.children?.flatMap { it.root.children }.orEmpty()
-                    if(parsed.size == 1 && parsed.first() is P){
-                        parsed.first().children
-                    } else {
-                        parsed
-                    }
-                }
-                "h1" -> ifChildrenPresent { H1(children) }
-                "h2" -> ifChildrenPresent { H2(children) }
-                "h3" -> ifChildrenPresent { H3(children) }
-                "var" -> ifChildrenPresent { Var(children) }
-                "u" -> ifChildrenPresent { U(children) }
-                else -> listOf(Text(body = element.ownText()))
-            }
-        }
-
-        private fun convertHtmlNode(node: Node, keepFormatting: Boolean = false): List = when (node) {
-            is TextNode -> (if (keepFormatting) {
-                node.wholeText.takeIf { it.isNotBlank() }?.let { listOf(Text(body = it)) }
-            } else {
-                node.wholeText.parseHtmlEncodedWithNormalisedSpaces(renderWhiteCharactersAsSpaces = true)
-            }).orEmpty()
-            is Comment -> listOf(Text(body = node.outerHtml(), params = DocTag.contentTypeParam("html")))
-            is Element -> createBlock(node, keepFormatting)
-            else -> emptyList()
-        }
-
-        override fun invoke(
-            elements: Iterable,
-            asParagraph: Boolean,
-            context: CommentResolutionContext
-        ): List =
-            elements.fold(ParsingResult(context.tag)) { acc, e ->
-                acc + e.stringify(acc.newState, context)
-            }.parsedLine?.let {
-                val trimmed = it.trim()
-                val toParse = if (asParagraph) "

$trimmed

" else trimmed - Jsoup.parseBodyFragment(toParse).body().childNodes().flatMap { convertHtmlNode(it) } - }.orEmpty() - } - - private fun convertJavadocElements( - elements: Iterable, - asParagraph: Boolean = true, - context: CommentResolutionContext - ): List = - Parse()(elements, asParagraph, context) - - private fun PsiDocToken.isSharpToken() = tokenType == JavaDocTokenType.DOC_TAG_VALUE_SHARP_TOKEN - - private fun PsiDocToken.isTagName() = tokenType == JavaDocTokenType.DOC_TAG_NAME - - private fun PsiDocToken.isLeadingAsterisk() = tokenType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS - - private fun PsiElement.toDocumentationLink(labelElement: PsiElement? = null, context: CommentResolutionContext) = - resolveToGetDri()?.let { - val dri = DRI.from(it) - val label = labelElement ?: defaultLabel() - DocumentationLink(dri, convertJavadocElements(listOfNotNull(label), asParagraph = false, context)) - } - - private fun PsiDocTag.referenceElement(): PsiElement? = - linkElement()?.referenceElementOrSelf() - - private fun PsiElement.defaultLabel() = children.firstOrNull { - it is PsiDocToken && it.text.isNotBlank() && !it.isSharpToken() - } ?: this - - private fun PsiDocTag.linkElement(): PsiElement? = - valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace } - - companion object { - private const val UNRESOLVED_PSI_ELEMENT = "UNRESOLVED_PSI_ELEMENT" - } -} diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt index 5b3be7e33ac..e69de29bb2d 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt @@ -1,32 +0,0 @@ -package org.jetbrains.dokka.base.translators.psi.parsers - -internal enum class JavadocTag { - PARAM, THROWS, RETURN, AUTHOR, SEE, DEPRECATED, EXCEPTION, HIDE, SINCE, - - /** - * Artificial tag created to handle tag-less section - */ - DESCRIPTION,; - - override fun toString(): String = super.toString().toLowerCase() - - /* Missing tags: - SERIAL, - SERIAL_DATA, - SERIAL_FIELD, - SINCE, - VERSION - */ - - companion object { - private val name2Value = values().associateBy { it.name.toLowerCase() } - - /** - * Lowercase-based `Enum.valueOf` variation for [JavadocTag]. - * - * Note: tags are [case-sensitive](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html) in Java, - * thus we are not allowed to use case-insensitive or uppercase-based lookup. - */ - fun lowercaseValueOfOrNull(name: String): JavadocTag? = name2Value[name] - } -} diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/PsiCommentsUtils.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/PsiCommentsUtils.kt deleted file mode 100644 index c4c8cbb2666..00000000000 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/PsiCommentsUtils.kt +++ /dev/null @@ -1,146 +0,0 @@ -package org.jetbrains.dokka.base.translators.psi.parsers - -import com.intellij.psi.* -import com.intellij.psi.javadoc.PsiDocComment -import com.intellij.psi.javadoc.PsiDocTag -import org.jetbrains.dokka.analysis.from -import org.jetbrains.dokka.base.translators.psi.findSuperMethodsOrEmptyArray -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName -import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull - -internal interface DocComment { - fun hasTag(tag: JavadocTag): Boolean - fun hasTagWithExceptionOfType(tag: JavadocTag, exceptionFqName: String): Boolean - fun tagsByName(tag: JavadocTag, param: String? = null): List -} - -internal data class JavaDocComment(val comment: PsiDocComment) : DocComment { - override fun hasTag(tag: JavadocTag): Boolean = comment.hasTag(tag) - override fun hasTagWithExceptionOfType(tag: JavadocTag, exceptionFqName: String): Boolean = - comment.hasTag(tag) && comment.tagsByName(tag).firstIsInstanceOrNull() - ?.resolveToElement() - ?.getKotlinFqName()?.asString() == exceptionFqName - - override fun tagsByName(tag: JavadocTag, param: String?): List = - comment.tagsByName(tag).map { PsiDocumentationContent(it, tag) } -} - -internal data class KotlinDocComment(val comment: KDocTag, val descriptor: DeclarationDescriptor) : DocComment { - override fun hasTag(tag: JavadocTag): Boolean = - when (tag) { - JavadocTag.DESCRIPTION -> comment.getContent().isNotEmpty() - else -> tagsWithContent.any { it.text.startsWith("@$tag") } - } - - override fun hasTagWithExceptionOfType(tag: JavadocTag, exceptionFqName: String): Boolean = - tagsWithContent.any { it.hasExceptionWithName(tag, exceptionFqName) } - - override fun tagsByName(tag: JavadocTag, param: String?): List = - when (tag) { - JavadocTag.DESCRIPTION -> listOf(DescriptorDocumentationContent(descriptor, comment, tag)) - else -> comment.children.mapNotNull { (it as? KDocTag) } - .filter { it.name == "$tag" && param?.let { param -> it.hasExceptionWithName(param) } != false } - .map { DescriptorDocumentationContent(descriptor, it, tag) } - } - - private val tagsWithContent: List = comment.children.mapNotNull { (it as? KDocTag) } - - private fun KDocTag.hasExceptionWithName(tag: JavadocTag, exceptionFqName: String) = - text.startsWith("@$tag") && hasExceptionWithName(exceptionFqName) - - private fun KDocTag.hasExceptionWithName(exceptionFqName: String) = - getSubjectName() == exceptionFqName -} - -internal interface DocumentationContent { - val tag: JavadocTag -} - -internal data class PsiDocumentationContent(val psiElement: PsiElement, override val tag: JavadocTag) : - DocumentationContent - -internal data class DescriptorDocumentationContent( - val descriptor: DeclarationDescriptor, - val element: KDocTag, - override val tag: JavadocTag -) : DocumentationContent - -internal fun PsiDocComment.hasTag(tag: JavadocTag): Boolean = - when (tag) { - JavadocTag.DESCRIPTION -> descriptionElements.isNotEmpty() - else -> findTagByName(tag.toString()) != null - } - -internal fun PsiDocComment.tagsByName(tag: JavadocTag): List = - when (tag) { - JavadocTag.DESCRIPTION -> descriptionElements.toList() - else -> findTagsByName(tag.toString()).toList() - } - -internal fun findClosestDocComment(element: PsiNamedElement, logger: DokkaLogger): DocComment? { - (element as? PsiDocCommentOwner)?.docComment?.run { return JavaDocComment(this) } - element.toKdocComment()?.run { return this } - - if (element is PsiMethod) { - val superMethods = element.findSuperMethodsOrEmptyArray(logger) - if (superMethods.isEmpty()) return null - - if (superMethods.size == 1) { - return findClosestDocComment(superMethods.single(), logger) - } - - val superMethodDocumentation = superMethods.map { method -> findClosestDocComment(method, logger) }.distinct() - if (superMethodDocumentation.size == 1) { - return superMethodDocumentation.single() - } - - logger.debug( - "Conflicting documentation for ${DRI.from(element)}" + - "${superMethods.map { DRI.from(it) }}" - ) - - /* Prioritize super class over interface */ - val indexOfSuperClass = superMethods.indexOfFirst { method -> - val parent = method.parent - if (parent is PsiClass) !parent.isInterface - else false - } - - return if (indexOfSuperClass >= 0) superMethodDocumentation[indexOfSuperClass] - else superMethodDocumentation.first() - } - return element.children.firstIsInstanceOrNull()?.let { JavaDocComment(it) } -} - -internal fun PsiNamedElement.toKdocComment(): KotlinDocComment? = - (navigationElement as? KtElement)?.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) } - ?.run { - (this@toKdocComment.navigationElement as? KtDeclaration)?.descriptor?.let { - KotlinDocComment( - this, - it - ) - } - } - -internal fun PsiDocTag.contentElementsWithSiblingIfNeeded(): List = if (dataElements.isNotEmpty()) { - listOfNotNull( - dataElements[0], - dataElements[0].nextSibling?.takeIf { it.text != dataElements.drop(1).firstOrNull()?.text }, - *dataElements.drop(1).toTypedArray() - ) -} else { - emptyList() -} - -internal fun PsiDocTag.resolveToElement(): PsiElement? = - dataElements.firstOrNull()?.firstChild?.referenceElementOrSelf()?.resolveToGetDri() diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/exceptionTag.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/exceptionTag.kt deleted file mode 100644 index 3cc16251b56..00000000000 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/exceptionTag.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.jetbrains.dokka.base.translators.psi.parsers - -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiJavaCodeReferenceElement -import com.intellij.psi.impl.source.tree.JavaDocElementType -import com.intellij.psi.util.PsiTreeUtil - -internal fun PsiElement.referenceElementOrSelf(): PsiElement? = - if (node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) { - PsiTreeUtil.findChildOfType(this, PsiJavaCodeReferenceElement::class.java) - } else this - -internal fun PsiElement.resolveToGetDri(): PsiElement? = - reference?.resolve() \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/translators/CollectionExtensions.kt b/plugins/base/src/main/kotlin/utils/CollectionExtensions.kt similarity index 88% rename from plugins/base/src/main/kotlin/translators/CollectionExtensions.kt rename to plugins/base/src/main/kotlin/utils/CollectionExtensions.kt index 0de4b5b112f..6fc5271fee4 100644 --- a/plugins/base/src/main/kotlin/translators/CollectionExtensions.kt +++ b/plugins/base/src/main/kotlin/utils/CollectionExtensions.kt @@ -1,4 +1,4 @@ -package org.jetbrains.dokka.base.translators +package org.jetbrains.dokka.base.utils // TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5 internal inline fun Iterable.firstNotNullOfOrNull(transform: (T) -> R?): R? { diff --git a/plugins/base/src/test/kotlin/basic/DRITest.kt b/plugins/base/src/test/kotlin/basic/DRITest.kt index 3a4ff84d29c..9c4435678aa 100644 --- a/plugins/base/src/test/kotlin/basic/DRITest.kt +++ b/plugins/base/src/test/kotlin/basic/DRITest.kt @@ -1,5 +1,6 @@ package basic +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.* import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.Nullable @@ -8,7 +9,6 @@ import org.jetbrains.dokka.model.* import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.MemberPageNode -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt b/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt index 35e4e52f812..d4e307bedd9 100644 --- a/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt +++ b/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt @@ -1,10 +1,9 @@ package basic +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import kotlin.test.assertEquals class DokkaBasicTests : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt b/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt index 682a257ed26..bd8a79ef20d 100644 --- a/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt +++ b/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt @@ -1,8 +1,8 @@ package basic import org.jetbrains.dokka.DokkaException -import org.jetbrains.dokka.testApi.logger.TestLogger import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.testApi.logger.TestLogger import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.utilities.LoggingLevel diff --git a/plugins/base/src/test/kotlin/content/annotations/ContentForAnnotationsTest.kt b/plugins/base/src/test/kotlin/content/annotations/ContentForAnnotationsTest.kt index f7f7eb66bb0..2659fd867c9 100644 --- a/plugins/base/src/test/kotlin/content/annotations/ContentForAnnotationsTest.kt +++ b/plugins/base/src/test/kotlin/content/annotations/ContentForAnnotationsTest.kt @@ -1,15 +1,14 @@ package content.annotations import matchers.content.* -import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.base.utils.firstNotNullOfOrNull import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.ContentText import org.jetbrains.dokka.pages.MemberPageNode import org.jetbrains.dokka.pages.PackagePageNode -import org.jetbrains.kotlin.util.firstNotNullResult import org.junit.jupiter.api.Test import utils.ParamAttributes import utils.assertNotNull @@ -223,7 +222,7 @@ class ContentForAnnotationsTest : BaseAbstractTest() { )) val property = modules.flatMap { it.packages }.flatMap { it.properties }.first() val annotation = property.extra[Annotations]?.let { - it.directAnnotations.entries.firstNotNullResult { (_, annotations) -> annotations.firstOrNull() } + it.directAnnotations.entries.firstNotNullOfOrNull { (_, annotations) -> annotations.firstOrNull() } } val annotationParams = annotation?.params ?: emptyMap() @@ -284,10 +283,10 @@ class ContentForAnnotationsTest : BaseAbstractTest() { val property = modules.flatMap { it.packages }.flatMap { it.properties }.first() val getterAnnotation = property.getter?.extra?.get(Annotations)?.let { - it.directAnnotations.entries.firstNotNullResult { (_, annotations) -> annotations.firstOrNull() } + it.directAnnotations.entries.firstNotNullOfOrNull { (_, annotations) -> annotations.firstOrNull() } } val setterAnnotation = property.getter?.extra?.get(Annotations)?.let { - it.directAnnotations.entries.firstNotNullResult { (_, annotations) -> annotations.firstOrNull() } + it.directAnnotations.entries.firstNotNullOfOrNull { (_, annotations) -> annotations.firstOrNull() } } assertEquals(expectedAnnotation("xd"), getterAnnotation) diff --git a/plugins/base/src/test/kotlin/content/annotations/KotlinDeprecatedTest.kt b/plugins/base/src/test/kotlin/content/annotations/KotlinDeprecatedTest.kt index 8b311893775..8351725467c 100644 --- a/plugins/base/src/test/kotlin/content/annotations/KotlinDeprecatedTest.kt +++ b/plugins/base/src/test/kotlin/content/annotations/KotlinDeprecatedTest.kt @@ -1,13 +1,13 @@ package content.annotations import matchers.content.* -import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.base.transformers.documentables.deprecatedAnnotation -import org.jetbrains.dokka.pages.ContentStyle import org.jetbrains.dokka.base.transformers.documentables.isDeprecated import org.jetbrains.dokka.model.Documentable 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.ParamAttributes import utils.bareSignature diff --git a/plugins/base/src/test/kotlin/content/annotations/SinceKotlinTest.kt b/plugins/base/src/test/kotlin/content/annotations/SinceKotlinTest.kt index d658b50b0e0..0b36031cf07 100644 --- a/plugins/base/src/test/kotlin/content/annotations/SinceKotlinTest.kt +++ b/plugins/base/src/test/kotlin/content/annotations/SinceKotlinTest.kt @@ -9,7 +9,9 @@ import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.doc.CustomTagWrapper import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.pages.ContentPage -import org.junit.jupiter.api.* +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import signatures.AbstractRenderingTest import utils.ParamAttributes import utils.TestOutputWriterPlugin diff --git a/plugins/base/src/test/kotlin/content/exceptions/ContentForExceptions.kt b/plugins/base/src/test/kotlin/content/exceptions/ContentForExceptions.kt index f59ba529319..14a36611145 100644 --- a/plugins/base/src/test/kotlin/content/exceptions/ContentForExceptions.kt +++ b/plugins/base/src/test/kotlin/content/exceptions/ContentForExceptions.kt @@ -6,7 +6,6 @@ import org.jetbrains.dokka.PluginConfigurationImpl import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.DisplaySourceSet -import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.Test import utils.ParamAttributes import utils.bareSignature @@ -47,7 +46,7 @@ class ContentForExceptions : BaseAbstractTest() { sourceRoots = listOf("src/linuxX64Main/kotlin/pageMerger/Test.kt") } } - pluginsConfigurations.addIfNotNull( + pluginsConfigurations.add( PluginConfigurationImpl( DokkaBase::class.qualifiedName!!, DokkaConfiguration.SerializationFormat.JSON, @@ -431,4 +430,4 @@ class ContentForExceptions : BaseAbstractTest() { private fun Set.assertSourceSet(expectedName: String) { assertEquals(1, this.size) assertEquals(expectedName, this.first().name) -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/content/inheritors/ContentForInheritorsTest.kt b/plugins/base/src/test/kotlin/content/inheritors/ContentForInheritorsTest.kt index 09c927bdf4e..e5059073764 100644 --- a/plugins/base/src/test/kotlin/content/inheritors/ContentForInheritorsTest.kt +++ b/plugins/base/src/test/kotlin/content/inheritors/ContentForInheritorsTest.kt @@ -5,7 +5,6 @@ import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.PluginConfigurationImpl import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.Test import utils.classSignature import utils.findTestType @@ -45,7 +44,7 @@ class ContentForInheritorsTest : BaseAbstractTest() { sourceRoots = listOf("src/linuxX64Main/kotlin/pageMerger/Test.kt") } } - pluginsConfigurations.addIfNotNull( + pluginsConfigurations.add( PluginConfigurationImpl( DokkaBase::class.qualifiedName!!, DokkaConfiguration.SerializationFormat.JSON, @@ -491,4 +490,4 @@ class ContentForInheritorsTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt b/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt index 742c801fbee..62c74671130 100644 --- a/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt +++ b/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt @@ -9,7 +9,6 @@ import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.Param import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.junit.jupiter.api.Test import utils.* import kotlin.test.assertEquals @@ -1514,6 +1513,6 @@ class ContentForParamsTest : BaseAbstractTest() { } private fun DocumentationNode.paramsDescription(): String = - children.firstIsInstanceOrNull()?.root?.children?.first()?.children?.firstIsInstanceOrNull()?.body.orEmpty() + children.filterIsInstance().firstOrNull()?.root?.children?.first()?.children?.filterIsInstance()?.firstOrNull()?.body.orEmpty() } diff --git a/plugins/base/src/test/kotlin/content/signatures/ContentForSignaturesTest.kt b/plugins/base/src/test/kotlin/content/signatures/ContentForSignaturesTest.kt index 3497317cf5f..a39ade2569a 100644 --- a/plugins/base/src/test/kotlin/content/signatures/ContentForSignaturesTest.kt +++ b/plugins/base/src/test/kotlin/content/signatures/ContentForSignaturesTest.kt @@ -2,10 +2,9 @@ package content.signatures import matchers.content.* import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.PackagePageNode import org.junit.jupiter.api.Test import utils.ParamAttributes import utils.bareSignature diff --git a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt index b3d56d2ea71..1602a7cf36e 100644 --- a/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/JavaEnumsTest.kt @@ -2,14 +2,11 @@ package enums import org.jetbrains.dokka.SourceLinkDefinitionImpl import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.model.ObviousMember import org.junit.jupiter.api.Test import signatures.renderedContent import utils.TestOutputWriterPlugin import java.net.URL import kotlin.test.assertEquals -import kotlin.test.assertNotNull class JavaEnumsTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt b/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt index 3b2720c9a3d..a49a29de9af 100644 --- a/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/KotlinEnumsTest.kt @@ -2,19 +2,19 @@ package enums import matchers.content.* import org.jetbrains.dokka.SourceLinkDefinitionImpl -import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.model.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.dfs +import org.jetbrains.dokka.pages.ClasslikePage +import org.jetbrains.dokka.pages.ClasslikePageNode +import org.jetbrains.dokka.pages.ContentGroup import org.jsoup.Jsoup import org.jsoup.nodes.Element import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import signatures.renderedContent import utils.TestOutputWriter import utils.TestOutputWriterPlugin -import java.io.File import java.net.URL class KotlinEnumsTest : BaseAbstractTest() { @@ -347,7 +347,7 @@ class KotlinEnumsTest : BaseAbstractTest() { configuration ) { pagesTransformationStage = { m -> - val entryNode = m.children.first { it.name == "testpackage" }.children.first { it.name == "TestEnum" }.children.firstIsInstance() + val entryNode = m.children.first { it.name == "testpackage" }.children.first { it.name == "TestEnum" }.children.filterIsInstance().first() val signature = (entryNode.content as ContentGroup).dfs { it is ContentGroup && it.dci.toString() == "[testpackage/TestEnum.E1///PointingToDeclaration/{\"org.jetbrains.dokka.links.EnumEntryDRIExtra\":{\"key\":\"org.jetbrains.dokka.links.EnumEntryDRIExtra\"}}][Cover]" } as ContentGroup signature.assertNode { diff --git a/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt b/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt index 13d4b4563b3..ff1b7989ee7 100644 --- a/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt +++ b/plugins/base/src/test/kotlin/expectActuals/ExpectActualsTest.kt @@ -1,11 +1,10 @@ package expectActuals +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.withDescendants import org.jetbrains.dokka.pages.ClasslikePageNode -import org.jetbrains.dokka.pages.PageNode -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test class ExpectActualsTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/filter/JavaFileFilterTest.kt b/plugins/base/src/test/kotlin/filter/JavaFileFilterTest.kt index f618292c8c5..a1a242c536d 100644 --- a/plugins/base/src/test/kotlin/filter/JavaFileFilterTest.kt +++ b/plugins/base/src/test/kotlin/filter/JavaFileFilterTest.kt @@ -3,7 +3,6 @@ package filter import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test -import kotlin.test.assertEquals class JavaFileFilterTest : BaseAbstractTest() { @Test diff --git a/plugins/base/src/test/kotlin/filter/KotlinArrayDocumentableReplacerTest.kt b/plugins/base/src/test/kotlin/filter/KotlinArrayDocumentableReplacerTest.kt index b9b1dc1eb57..de7c4e43ae1 100644 --- a/plugins/base/src/test/kotlin/filter/KotlinArrayDocumentableReplacerTest.kt +++ b/plugins/base/src/test/kotlin/filter/KotlinArrayDocumentableReplacerTest.kt @@ -1,9 +1,11 @@ package filter -import com.jetbrains.rd.util.firstOrNull import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.DClass +import org.jetbrains.dokka.model.FunctionalTypeConstructor +import org.jetbrains.dokka.model.GenericTypeConstructor +import org.jetbrains.dokka.model.Invariance import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -124,7 +126,7 @@ class KotlinArrayDocumentableReplacerTest : BaseAbstractTest() { val arrTypealias = it.firstOrNull()?.packages?.firstOrNull()?.typealiases?.firstOrNull() Assertions.assertEquals(GenericTypeConstructor(DRI("kotlin", "IntArray"), emptyList()), - arrTypealias?.underlyingType?.firstOrNull()?.value) + arrTypealias?.underlyingType?.values?.firstOrNull()) } } } @@ -196,4 +198,4 @@ class KotlinArrayDocumentableReplacerTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt index d7ac8b97234..a571a7e0dd3 100644 --- a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt +++ b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt @@ -2,14 +2,11 @@ package linkableContent import org.jetbrains.dokka.SourceLinkDefinitionImpl import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.base.transformers.pages.samples.DefaultSamplesTransformer import org.jetbrains.dokka.base.transformers.pages.sourcelinks.SourceLinksTransformer import org.jetbrains.dokka.model.WithGenerics import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.utils.addToStdlib.cast -import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jsoup.Jsoup import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -135,8 +132,8 @@ class LinkableContentTest : BaseAbstractTest() { Assertions.assertEquals(2, packageChildren.size) packageChildren.forEach { val name = it.name.substringBefore("Class") - val signature = it.safeAs()?.content?.dfs { it is ContentGroup && it.dci.kind == ContentKind.Symbol }.assertNotNull("signature") - val crl = signature.children.last().children[1].safeAs() + val signature = (it as? ClasslikePageNode)?.content?.dfs { it is ContentGroup && it.dci.kind == ContentKind.Symbol }.assertNotNull("signature") + val crl = signature.children.last().children[1] as? ContentResolvedLink Assertions.assertEquals( "https://github.com/user/repo/tree/master/src/${name.toLowerCase()}Main/kotlin/${name}Class.kt#L3", crl?.address @@ -188,8 +185,9 @@ class LinkableContentTest : BaseAbstractTest() { testFromData(configuration) { renderingStage = { rootPageNode, dokkaContext -> - val newRoot = DefaultSamplesTransformer(dokkaContext).invoke(rootPageNode) - + // TODO [beresnev] :((( +// val newRoot = DefaultSamplesTransformer(dokkaContext).invoke(rootPageNode) + val newRoot = rootPageNode val moduleChildren = newRoot.children Assertions.assertEquals(1, moduleChildren.size) val packageChildren = moduleChildren.first().children @@ -199,12 +197,13 @@ class LinkableContentTest : BaseAbstractTest() { val classChildren = pageNode.children Assertions.assertEquals(2, classChildren.size) val function = classChildren.find { it.name == "printWithExclamation" } - val text = function.cast().content.cast().children.last() - .cast().children.single() - .cast().after - .cast().children.last() - .cast().children.single() - .cast().children.single().cast().text + val text = (function as MemberPageNode).content.let { it as ContentGroup }.children.last() + .let { it as ContentDivergentGroup }.children.single() + .let { it as ContentDivergentInstance }.after + .let { it as ContentGroup }.children.last() + .let { it as ContentGroup }.children.single() + .let { it as ContentCodeBlock }.children.single() + .let { it as ContentText }.text Assertions.assertEquals( """|import p2.${name}Class |fun main() { @@ -245,16 +244,20 @@ class LinkableContentTest : BaseAbstractTest() { ) { renderingStage = { module, _ -> val sample = module.children.single { it.name == "test" } - .children.single { it.name == "Sample" }.cast() + .children.single { it.name == "Sample" } as ClasslikePageNode val foo = sample - .children.single { it.name == "SampleInner" }.cast() - .children.single { it.name == "foo" }.cast() + .children + .single { it.name == "SampleInner" } + .let { it as ClasslikePageNode } + .children + .single { it.name == "foo" } + .let { it as MemberPageNode } val returnTypeNode = foo.content.dfs { - val link = it.safeAs()?.children - val child = link?.first().safeAs() + val link = (it as? ContentDRILink)?.children + val child = link?.first() as? ContentText child?.text == "S" - }?.safeAs() + } as? ContentDRILink Assertions.assertEquals( (sample.documentables.firstOrNull() as WithGenerics).generics.first().dri, diff --git a/plugins/base/src/test/kotlin/linking/EnumValuesLinkingTest.kt b/plugins/base/src/test/kotlin/linking/EnumValuesLinkingTest.kt index f95d9860ed7..14875832086 100644 --- a/plugins/base/src/test/kotlin/linking/EnumValuesLinkingTest.kt +++ b/plugins/base/src/test/kotlin/linking/EnumValuesLinkingTest.kt @@ -7,13 +7,12 @@ import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.doc.DocumentationLink import org.jetbrains.dokka.pages.ContentDRILink import org.jetbrains.dokka.pages.ContentPage -import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jsoup.Jsoup -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test -import java.nio.file.Paths import utils.TestOutputWriterPlugin -import kotlin.AssertionError +import java.nio.file.Paths class EnumValuesLinkingTest : BaseAbstractTest() { @@ -80,13 +79,13 @@ class EnumValuesLinkingTest : BaseAbstractTest() { } assertEquals( - javaLinker.documentation.values.single().children[0].children[1].children[1].safeAs()?.dri, - kotlinLinker.documentation.values.single().children[0].children[0].children[5].safeAs()?.dri + javaLinker.documentation.values.single().children[0].children[1].children[1].let { it as? DocumentationLink }?.dri, + kotlinLinker.documentation.values.single().children[0].children[0].children[5].let { it as? DocumentationLink }?.dri ) assertEquals( - javaLinker.documentation.values.single().children[0].children[2].children[1].safeAs()?.dri, - kotlinLinker.documentation.values.single().children[0].children[0].children[9].safeAs()?.dri + javaLinker.documentation.values.single().children[0].children[2].children[1].let { it as? DocumentationLink }?.dri, + kotlinLinker.documentation.values.single().children[0].children[0].children[9].let { it as? DocumentationLink }?.dri ) } diff --git a/plugins/base/src/test/kotlin/locationProvider/AndroidExternalLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/AndroidExternalLocationProviderTest.kt index 071997fcf25..e9e0871ae69 100644 --- a/plugins/base/src/test/kotlin/locationProvider/AndroidExternalLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/AndroidExternalLocationProviderTest.kt @@ -5,11 +5,11 @@ import org.jetbrains.dokka.base.resolvers.external.javadoc.AndroidExternalLocati import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation import org.jetbrains.dokka.base.resolvers.shared.PackageList import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.TypeConstructor import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.net.URL diff --git a/plugins/base/src/test/kotlin/locationProvider/DefaultExternalLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DefaultExternalLocationProviderTest.kt index 3a8aafa7823..870d8cf3c00 100644 --- a/plugins/base/src/test/kotlin/locationProvider/DefaultExternalLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/DefaultExternalLocationProviderTest.kt @@ -3,11 +3,11 @@ package locationProvider import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation import org.jetbrains.dokka.base.resolvers.shared.PackageList +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.TypeConstructor import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.net.URL diff --git a/plugins/base/src/test/kotlin/locationProvider/Dokka010ExternalLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/Dokka010ExternalLocationProviderTest.kt index 809507472ce..241e0919684 100644 --- a/plugins/base/src/test/kotlin/locationProvider/Dokka010ExternalLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/Dokka010ExternalLocationProviderTest.kt @@ -3,11 +3,11 @@ package locationProvider import org.jetbrains.dokka.base.resolvers.external.Dokka010ExternalLocationProvider import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation import org.jetbrains.dokka.base.resolvers.shared.PackageList +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.TypeConstructor import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.net.URL diff --git a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt index 59406e1e60b..f43a4cd7af1 100644 --- a/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt @@ -5,7 +5,6 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.kotlin.backend.common.push import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -49,7 +48,7 @@ class DokkaLocationProviderTest : BaseAbstractTest() { class ModulesDsl(val pages: MutableList = mutableListOf()) { fun modulePage(name: String, fn: PackageDsl.() -> Unit) { val packages = PackageDsl().also { it.fn() } - pages.push( + pages.add( ModulePageNode( name = name, children = packages.pages, @@ -63,7 +62,7 @@ class DokkaLocationProviderTest : BaseAbstractTest() { class PackageDsl(val pages: MutableList = mutableListOf()) { fun packagePage(name: String, fn: ClassDsl.() -> Unit) { val packages = ClassDsl().also { it.fn() } - pages.push( + pages.add( PackagePageNode( name = name, children = packages.pages, @@ -77,7 +76,7 @@ class DokkaLocationProviderTest : BaseAbstractTest() { @TestNavigationDSL class ClassDsl(val pages: MutableList = mutableListOf()) { fun classPage(name: String) { - pages.push( + pages.add( ClasslikePageNode( name = name, children = emptyList(), diff --git a/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt b/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt index 95179e227b6..27e51caf50c 100644 --- a/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt @@ -4,9 +4,12 @@ import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvid 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.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DRIExtraContainer +import org.jetbrains.dokka.links.EnumEntryDRIExtra +import org.jetbrains.dokka.links.PointingToDeclaration +import org.jetbrains.dokka.plugability.DokkaContext import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.net.URL diff --git a/plugins/base/src/test/kotlin/locationProvider/MultiModuleLinkingTest.kt b/plugins/base/src/test/kotlin/locationProvider/MultiModuleLinkingTest.kt index aefe913cf0f..031dd101b7f 100644 --- a/plugins/base/src/test/kotlin/locationProvider/MultiModuleLinkingTest.kt +++ b/plugins/base/src/test/kotlin/locationProvider/MultiModuleLinkingTest.kt @@ -3,11 +3,10 @@ package locationProvider import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation import org.jetbrains.dokka.base.resolvers.shared.PackageList +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import java.net.URL diff --git a/plugins/base/src/test/kotlin/markdown/KDocTest.kt b/plugins/base/src/test/kotlin/markdown/KDocTest.kt index fddd41e756e..698859310f5 100644 --- a/plugins/base/src/test/kotlin/markdown/KDocTest.kt +++ b/plugins/base/src/test/kotlin/markdown/KDocTest.kt @@ -1,10 +1,10 @@ package markdown +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.DPackage import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.jupiter.api.Assertions.* -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.junit.jupiter.api.Assertions.assertEquals abstract class KDocTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/markdown/LinkTest.kt b/plugins/base/src/test/kotlin/markdown/LinkTest.kt index f141bb06851..526ff0eb3f8 100644 --- a/plugins/base/src/test/kotlin/markdown/LinkTest.kt +++ b/plugins/base/src/test/kotlin/markdown/LinkTest.kt @@ -1,13 +1,13 @@ package markdown +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.* import org.jetbrains.dokka.model.WithGenerics import org.jetbrains.dokka.model.dfs +import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ContentDRILink import org.jetbrains.dokka.pages.MemberPageNode -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.links.* -import org.jetbrains.dokka.model.doc.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test diff --git a/plugins/base/src/test/kotlin/markdown/ParserTest.kt b/plugins/base/src/test/kotlin/markdown/ParserTest.kt index fd723263154..b2d777c5b52 100644 --- a/plugins/base/src/test/kotlin/markdown/ParserTest.kt +++ b/plugins/base/src/test/kotlin/markdown/ParserTest.kt @@ -1,8 +1,9 @@ package org.jetbrains.dokka.tests import markdown.KDocTest -import org.intellij.markdown.MarkdownElementTypes -import org.jetbrains.dokka.base.parsers.MarkdownParser + +import org.jetbrains.dokka.analysis.markdown.MARKDOWN_FILE_NAME +import org.jetbrains.dokka.analysis.markdown.MarkdownParser import org.jetbrains.dokka.model.doc.* import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -25,7 +26,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(Text("This is simple test of string Next line")))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -52,7 +53,7 @@ class ParserTest : KDocTest() { ) ) ), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -81,7 +82,7 @@ class ParserTest : KDocTest() { B(listOf(I(listOf(Text("line"))))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -99,7 +100,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(Text("This is simple text with: colon!")))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -119,7 +120,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(Text("Text and String")))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -143,7 +144,7 @@ class ParserTest : KDocTest() { listOf( P(listOf(Text("Paragraph number one"))), P(listOf(Text("Paragraph"), Br, Text("number two"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -159,7 +160,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(I(listOf(Text("text")))))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -175,7 +176,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(Text("text_with_underscores")))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -191,7 +192,7 @@ class ParserTest : KDocTest() { Description( CustomDocTag( listOf(P(listOf(I(listOf(Text("text")))))), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -220,7 +221,7 @@ class ParserTest : KDocTest() { Text("x\".") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -249,7 +250,7 @@ class ParserTest : KDocTest() { Text("x\".") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -266,7 +267,7 @@ class ParserTest : KDocTest() { CustomDocTag( listOf( P(listOf(Text("Embedded*Star"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -292,7 +293,7 @@ class ParserTest : KDocTest() { Li(listOf(P(listOf(Text("list item 2"))))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -319,7 +320,7 @@ class ParserTest : KDocTest() { Li(listOf(P(listOf(Text("list item 2"), Br, Text("continue 2"))))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -366,7 +367,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -414,7 +415,7 @@ class ParserTest : KDocTest() { ) ), P(listOf(Text("New paragraph"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -440,7 +441,7 @@ class ParserTest : KDocTest() { ), mapOf("start" to "1") ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -467,7 +468,7 @@ class ParserTest : KDocTest() { ), mapOf("start" to "9") ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -495,7 +496,7 @@ class ParserTest : KDocTest() { ), mapOf("start" to "2") ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -543,7 +544,7 @@ class ParserTest : KDocTest() { ), mapOf("start" to "1") ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -594,7 +595,7 @@ class ParserTest : KDocTest() { mapOf("start" to "1") ), P(listOf(Text("New paragraph"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -644,7 +645,7 @@ class ParserTest : KDocTest() { mapOf("start" to "1") ), P(listOf(Text("New paragraph"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -668,7 +669,7 @@ class ParserTest : KDocTest() { H1(listOf(Text("Header 1"))), P(listOf(Text("Following text"))), P(listOf(Text("New paragraph"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -710,7 +711,7 @@ class ParserTest : KDocTest() { P(listOf(Text("Text 5"))), H6(listOf(Text("Header 6"))), P(listOf(Text("Text 6"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -736,7 +737,7 @@ class ParserTest : KDocTest() { B(listOf(Text("line 2"))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -771,7 +772,7 @@ class ParserTest : KDocTest() { HorizontalRule, P(listOf(Text("text 4"))), HorizontalRule - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -809,7 +810,7 @@ class ParserTest : KDocTest() { P(listOf(Text("Quote"))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -854,7 +855,7 @@ class ParserTest : KDocTest() { P(listOf(Text("Quote"))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -916,7 +917,7 @@ class ParserTest : KDocTest() { P(listOf(Text("Quote"))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -941,7 +942,7 @@ class ParserTest : KDocTest() { Text(" Sample text") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -982,7 +983,7 @@ class ParserTest : KDocTest() { mapOf("lang" to "kotlin") ), P(listOf(Text("Sample text"))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1009,7 +1010,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1035,7 +1036,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1063,7 +1064,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1091,7 +1092,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1121,7 +1122,7 @@ class ParserTest : KDocTest() { Text(".") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1151,7 +1152,7 @@ class ParserTest : KDocTest() { Text(" and sometimes example.com (but not on Github, for example).") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1240,7 +1241,7 @@ class ParserTest : KDocTest() { ) ), P(listOf(Text("Some text to show that the reference links can follow later."))) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1261,7 +1262,7 @@ class ParserTest : KDocTest() { Text("text text") ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1288,7 +1289,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1315,7 +1316,7 @@ class ParserTest : KDocTest() { A(listOf(Text("link to Google!")), mapOf("href" to "http://google.com")) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1348,7 +1349,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1413,7 +1414,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1437,7 +1438,7 @@ class ParserTest : KDocTest() { Strikethrough(listOf(Text("strikethroughed"))) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1464,7 +1465,7 @@ class ParserTest : KDocTest() { ) ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) @@ -1514,7 +1515,7 @@ class ParserTest : KDocTest() { ) ) ), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_FILE_NAME ) ) ) @@ -1537,7 +1538,7 @@ class ParserTest : KDocTest() { CodeInline(listOf(Text("``` "))), ) ) - ), name = MarkdownElementTypes.MARKDOWN_FILE.name + ), name = MARKDOWN_FILE_NAME ) ) ) diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt index 920dea10238..6a3e80cd892 100644 --- a/plugins/base/src/test/kotlin/model/ClassesTest.kt +++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt @@ -1,6 +1,7 @@ package model import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.TypeConstructor import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.KotlinModifier.* @@ -10,7 +11,6 @@ import utils.AbstractModelTest import utils.assertNotNull import utils.name import utils.supers -import org.jetbrains.dokka.links.TypeConstructor class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "classes") { diff --git a/plugins/base/src/test/kotlin/model/CommentTest.kt b/plugins/base/src/test/kotlin/model/CommentTest.kt index 7f2151bc697..cd149209f97 100644 --- a/plugins/base/src/test/kotlin/model/CommentTest.kt +++ b/plugins/base/src/test/kotlin/model/CommentTest.kt @@ -3,9 +3,11 @@ package model import org.jetbrains.dokka.model.DClass import org.jetbrains.dokka.model.DProperty import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Br import org.junit.jupiter.api.Test -import utils.* +import utils.AbstractModelTest +import utils.assertNotNull +import utils.comments +import utils.docs class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comment") { diff --git a/plugins/base/src/test/kotlin/model/ExtensionsTest.kt b/plugins/base/src/test/kotlin/model/ExtensionsTest.kt index f2657ef8f85..e28b442fb96 100644 --- a/plugins/base/src/test/kotlin/model/ExtensionsTest.kt +++ b/plugins/base/src/test/kotlin/model/ExtensionsTest.kt @@ -1,10 +1,13 @@ package model import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions -import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.DClass +import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.model.DInterface +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.properties.WithExtraProperties import org.junit.jupiter.api.Test import utils.AbstractModelTest -import org.jetbrains.dokka.model.properties.WithExtraProperties class ExtensionsTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "classes") { private fun , R : Documentable> T.checkExtension(name: String = "extension") = @@ -149,4 +152,4 @@ class ExtensionsTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "cl } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/model/InheritorsTest.kt b/plugins/base/src/test/kotlin/model/InheritorsTest.kt index 265bb7a09b4..641f6ef5087 100644 --- a/plugins/base/src/test/kotlin/model/InheritorsTest.kt +++ b/plugins/base/src/test/kotlin/model/InheritorsTest.kt @@ -1,18 +1,12 @@ package model import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.DokkaAnalysisConfiguration -import org.jetbrains.dokka.analysis.ProjectKotlinAnalysis -import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo import org.jetbrains.dokka.model.DClass import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.model.DInterface import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import utils.AbstractModelTest @@ -155,220 +149,221 @@ class InheritorsTest : AbstractModelTest("/src/main/kotlin/inheritors/Test.kt", } } - class IgnoreCommonBuiltInsPlugin : DokkaPlugin() { - private val dokkaBase by lazy { plugin() } - @Suppress("unused") - val stdLibKotlinAnalysis by extending { - dokkaBase.kotlinAnalysis providing { ctx -> - ProjectKotlinAnalysis( - sourceSets = ctx.configuration.sourceSets, - logger = ctx.logger, - analysisConfiguration = DokkaAnalysisConfiguration(ignoreCommonBuiltIns = true) - ) - } override dokkaBase.defaultKotlinAnalysis - } - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = - PluginApiPreviewAcknowledgement - } - @Test - fun `should inherit docs for stdLib #2638`() { - val testConfiguration = dokkaConfiguration { - suppressObviousFunctions = false - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - analysisPlatform = "common" - languageVersion = "1.4" - } - } - } - - inlineModelTest( - """ - package kotlin.collections - - import kotlin.internal.PlatformDependent - - /** - * Classes that inherit from this interface can be represented as a sequence of elements that can - * be iterated over. - * @param T the type of element being iterated over. The iterator is covariant in its element type. - */ - public interface Iterable { - /** - * Returns an iterator over the elements of this object. - */ - public operator fun iterator(): Iterator - } - - /** - * Classes that inherit from this interface can be represented as a sequence of elements that can - * be iterated over and that supports removing elements during iteration. - * @param T the type of element being iterated over. The mutable iterator is invariant in its element type. - */ - public interface MutableIterable : Iterable { - /** - * Returns an iterator over the elements of this sequence that supports removing elements during iteration. - */ - override fun iterator(): MutableIterator - } - - /** - * A generic collection of elements. Methods in this interface support only read-only access to the collection; - * read/write access is supported through the [MutableCollection] interface. - * @param E the type of elements contained in the collection. The collection is covariant in its element type. - */ - public interface Collection : Iterable { - // Query Operations - /** - * Returns the size of the collection. - */ - public val size: Int - - /** - * Returns `true` if the collection is empty (contains no elements), `false` otherwise. - */ - public fun isEmpty(): Boolean - - /** - * Checks if the specified element is contained in this collection. - */ - public operator fun contains(element: @UnsafeVariance E): Boolean - - override fun iterator(): Iterator - - // Bulk Operations - /** - * Checks if all elements in the specified collection are contained in this collection. - */ - public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean - } - - /** - * A generic collection of elements that supports adding and removing elements. - * - * @param E the type of elements contained in the collection. The mutable collection is invariant in its element type. - */ - public interface MutableCollection : Collection, MutableIterable { - // Query Operations - override fun iterator(): MutableIterator - - // Modification Operations - /** - * Adds the specified element to the collection. - * - * @return `true` if the element has been added, `false` if the collection does not support duplicates - * and the element is already contained in the collection. - */ - public fun add(element: E): Boolean - - /** - * Removes a single instance of the specified element from this - * collection, if it is present. - * - * @return `true` if the element has been successfully removed; `false` if it was not present in the collection. - */ - public fun remove(element: E): Boolean - - // Bulk Modification Operations - /** - * Adds all of the elements of the specified collection to this collection. - * - * @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified. - */ - public fun addAll(elements: Collection): Boolean - - /** - * Removes all of this collection's elements that are also contained in the specified collection. - * - * @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified. - */ - public fun removeAll(elements: Collection): Boolean - - /** - * Retains only the elements in this collection that are contained in the specified collection. - * - * @return `true` if any element was removed from the collection, `false` if the collection was not modified. - */ - public fun retainAll(elements: Collection): Boolean - - /** - * Removes all elements from this collection. - */ - public fun clear(): Unit - } - - /** - * A generic ordered collection of elements. Methods in this interface support only read-only access to the list; - * read/write access is supported through the [MutableList] interface. - * @param E the type of elements contained in the list. The list is covariant in its element type. - */ - public interface List : Collection { - // Query Operations - - override val size: Int - override fun isEmpty(): Boolean - override fun contains(element: @UnsafeVariance E): Boolean - override fun iterator(): Iterator - - // Bulk Operations - override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean - - // Positional Access Operations - /** - * Returns the element at the specified index in the list. - */ - public operator fun get(index: Int): E - - // Search Operations - /** - * Returns the index of the first occurrence of the specified element in the list, or -1 if the specified - * element is not contained in the list. - */ - public fun indexOf(element: @UnsafeVariance E): Int - - /** - * Returns the index of the last occurrence of the specified element in the list, or -1 if the specified - * element is not contained in the list. - */ - public fun lastIndexOf(element: @UnsafeVariance E): Int - - // List Iterators - /** - * Returns a list iterator over the elements in this list (in proper sequence). - */ - public fun listIterator(): ListIterator - - /** - * Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index]. - */ - public fun listIterator(index: Int): ListIterator - - // View - /** - * Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive). - * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. - * - * Structural changes in the base list make the behavior of the view undefined. - */ - public fun subList(fromIndex: Int, toIndex: Int): List - } - - // etc - """.trimMargin(), - platform = Platform.common.toString(), - configuration = testConfiguration, - prependPackage = false, - pluginsOverrides = listOf(IgnoreCommonBuiltInsPlugin()) - ) { - with((this / "kotlin.collections" / "List" / "contains").cast()) { - documentation.size equals 1 - - } - } - } +// TODO [beresnev] fix, needs access to analysis +// class IgnoreCommonBuiltInsPlugin : DokkaPlugin() { +// private val kotlinAnalysisPlugin by lazy { plugin() } +// @Suppress("unused") +// val stdLibKotlinAnalysis by extending { +// kotlinAnalysisPlugin.kotlinAnalysis providing { ctx -> +// ProjectKotlinAnalysis( +// sourceSets = ctx.configuration.sourceSets, +// logger = ctx.logger, +// analysisConfiguration = DokkaAnalysisConfiguration(ignoreCommonBuiltIns = true) +// ) +// } override kotlinAnalysisPlugin.defaultKotlinAnalysis +// } +// +// @OptIn(DokkaPluginApiPreview::class) +// override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = +// PluginApiPreviewAcknowledgement +// } +// @Test +// fun `should inherit docs for stdLib #2638`() { +// val testConfiguration = dokkaConfiguration { +// suppressObviousFunctions = false +// sourceSets { +// sourceSet { +// sourceRoots = listOf("src/") +// analysisPlatform = "common" +// languageVersion = "1.4" +// } +// } +// } +// +// inlineModelTest( +// """ +// package kotlin.collections +// +// import kotlin.internal.PlatformDependent +// +// /** +// * Classes that inherit from this interface can be represented as a sequence of elements that can +// * be iterated over. +// * @param T the type of element being iterated over. The iterator is covariant in its element type. +// */ +// public interface Iterable { +// /** +// * Returns an iterator over the elements of this object. +// */ +// public operator fun iterator(): Iterator +// } +// +// /** +// * Classes that inherit from this interface can be represented as a sequence of elements that can +// * be iterated over and that supports removing elements during iteration. +// * @param T the type of element being iterated over. The mutable iterator is invariant in its element type. +// */ +// public interface MutableIterable : Iterable { +// /** +// * Returns an iterator over the elements of this sequence that supports removing elements during iteration. +// */ +// override fun iterator(): MutableIterator +// } +// +// /** +// * A generic collection of elements. Methods in this interface support only read-only access to the collection; +// * read/write access is supported through the [MutableCollection] interface. +// * @param E the type of elements contained in the collection. The collection is covariant in its element type. +// */ +// public interface Collection : Iterable { +// // Query Operations +// /** +// * Returns the size of the collection. +// */ +// public val size: Int +// +// /** +// * Returns `true` if the collection is empty (contains no elements), `false` otherwise. +// */ +// public fun isEmpty(): Boolean +// +// /** +// * Checks if the specified element is contained in this collection. +// */ +// public operator fun contains(element: @UnsafeVariance E): Boolean +// +// override fun iterator(): Iterator +// +// // Bulk Operations +// /** +// * Checks if all elements in the specified collection are contained in this collection. +// */ +// public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean +// } +// +// /** +// * A generic collection of elements that supports adding and removing elements. +// * +// * @param E the type of elements contained in the collection. The mutable collection is invariant in its element type. +// */ +// public interface MutableCollection : Collection, MutableIterable { +// // Query Operations +// override fun iterator(): MutableIterator +// +// // Modification Operations +// /** +// * Adds the specified element to the collection. +// * +// * @return `true` if the element has been added, `false` if the collection does not support duplicates +// * and the element is already contained in the collection. +// */ +// public fun add(element: E): Boolean +// +// /** +// * Removes a single instance of the specified element from this +// * collection, if it is present. +// * +// * @return `true` if the element has been successfully removed; `false` if it was not present in the collection. +// */ +// public fun remove(element: E): Boolean +// +// // Bulk Modification Operations +// /** +// * Adds all of the elements of the specified collection to this collection. +// * +// * @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified. +// */ +// public fun addAll(elements: Collection): Boolean +// +// /** +// * Removes all of this collection's elements that are also contained in the specified collection. +// * +// * @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified. +// */ +// public fun removeAll(elements: Collection): Boolean +// +// /** +// * Retains only the elements in this collection that are contained in the specified collection. +// * +// * @return `true` if any element was removed from the collection, `false` if the collection was not modified. +// */ +// public fun retainAll(elements: Collection): Boolean +// +// /** +// * Removes all elements from this collection. +// */ +// public fun clear(): Unit +// } +// +// /** +// * A generic ordered collection of elements. Methods in this interface support only read-only access to the list; +// * read/write access is supported through the [MutableList] interface. +// * @param E the type of elements contained in the list. The list is covariant in its element type. +// */ +// public interface List : Collection { +// // Query Operations +// +// override val size: Int +// override fun isEmpty(): Boolean +// override fun contains(element: @UnsafeVariance E): Boolean +// override fun iterator(): Iterator +// +// // Bulk Operations +// override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean +// +// // Positional Access Operations +// /** +// * Returns the element at the specified index in the list. +// */ +// public operator fun get(index: Int): E +// +// // Search Operations +// /** +// * Returns the index of the first occurrence of the specified element in the list, or -1 if the specified +// * element is not contained in the list. +// */ +// public fun indexOf(element: @UnsafeVariance E): Int +// +// /** +// * Returns the index of the last occurrence of the specified element in the list, or -1 if the specified +// * element is not contained in the list. +// */ +// public fun lastIndexOf(element: @UnsafeVariance E): Int +// +// // List Iterators +// /** +// * Returns a list iterator over the elements in this list (in proper sequence). +// */ +// public fun listIterator(): ListIterator +// +// /** +// * Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index]. +// */ +// public fun listIterator(index: Int): ListIterator +// +// // View +// /** +// * Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive). +// * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. +// * +// * Structural changes in the base list make the behavior of the view undefined. +// */ +// public fun subList(fromIndex: Int, toIndex: Int): List +// } +// +// // etc +// """.trimMargin(), +// platform = Platform.common.toString(), +// configuration = testConfiguration, +// prependPackage = false, +// pluginsOverrides = listOf(IgnoreCommonBuiltInsPlugin()) +// ) { +// with((this / "kotlin.collections" / "List" / "contains").cast()) { +// documentation.size equals 1 +// +// } +// } +// } @Test fun `should inherit docs in case of diamond inheritance`() { diff --git a/plugins/base/src/test/kotlin/model/MultiLanguageInheritanceTest.kt b/plugins/base/src/test/kotlin/model/MultiLanguageInheritanceTest.kt index a163f7f4dce..78f619d8402 100644 --- a/plugins/base/src/test/kotlin/model/MultiLanguageInheritanceTest.kt +++ b/plugins/base/src/test/kotlin/model/MultiLanguageInheritanceTest.kt @@ -3,13 +3,9 @@ package model import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.PointingToDeclaration -import org.jetbrains.dokka.model.childrenOfType import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.firstMemberOfType import org.jetbrains.dokka.model.withDescendants -import org.jetbrains.dokka.pages.ContentText -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.junit.jupiter.api.Test import translators.documentationOf import utils.docs @@ -57,7 +53,7 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { documentablesMergingStage = { module -> val function = module.packages.flatMap { it.classlikes } .find { it.name == "Child" }?.functions?.find { it.name == "parentFunction" } - val seeTag = function?.documentation?.values?.first()?.children?.firstIsInstanceOrNull() + val seeTag = function?.documentation?.values?.first()?.children?.filterIsInstance()?.firstOrNull() assertEquals("", module.documentationOf("Child")) assertEquals("parent function docs", module.documentationOf("Child", "parentFunction")) @@ -106,7 +102,7 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { documentablesMergingStage = { module -> val function = module.packages.flatMap { it.classlikes } .find { it.name == "ChildInJava" }?.functions?.find { it.name == "parentFun" } - val seeTag = function?.documentation?.values?.first()?.children?.firstIsInstanceOrNull() + val seeTag = function?.documentation?.values?.first()?.children?.filterIsInstance()?.firstOrNull() val expectedDocs = CustomDocTag( children = listOf( @@ -128,7 +124,7 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { ) assertEquals("", module.documentationOf("ChildInJava")) - assertEquals(expectedDocs, function?.docs()?.firstIsInstanceOrNull()?.root) + assertEquals(expectedDocs, function?.docs()?.filterIsInstance()?.firstOrNull()?.root) assertEquals("for details", (seeTag?.root?.dfs { it is Text } as Text).body) assertEquals("java.lang.String", seeTag.name) } @@ -206,7 +202,7 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { ) assertEquals("", module.documentationOf("ChildInJava")) - assertEquals(expectedDocs, function?.docs()?.firstIsInstanceOrNull()?.root) + assertEquals(expectedDocs, function?.docs()?.filterIsInstance()?.firstOrNull()?.root) } } } @@ -296,7 +292,7 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { val function = module.packages.flatMap { it.classlikes } .find { it.name == "ChildInJava" }?.functions?.find { it.name == "parentFun" } val docs = function?.documentation?.values?.first()?.children?.first() - val throwsTag = function?.documentation?.values?.first()?.children?.firstIsInstanceOrNull() + val throwsTag = function?.documentation?.values?.first()?.children?.filterIsInstance()?.firstOrNull() assertEquals("", module.documentationOf("ChildInJava")) assertEquals("Start parent function docs end", docs?.root?.withDescendants()?.filter { it is Text }?.toList()?.joinToString("") { (it as Text).body }) @@ -361,4 +357,4 @@ class MultiLanguageInheritanceTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/model/PropertyTest.kt b/plugins/base/src/test/kotlin/model/PropertyTest.kt index 1047d6cfab2..d38667bfff3 100644 --- a/plugins/base/src/test/kotlin/model/PropertyTest.kt +++ b/plugins/base/src/test/kotlin/model/PropertyTest.kt @@ -1,13 +1,10 @@ package model -import org.jetbrains.dokka.links.Callable -import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* import org.junit.jupiter.api.Test import utils.AbstractModelTest import utils.assertNotNull import utils.name -import kotlin.test.assertEquals class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "property") { diff --git a/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt b/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt index 1a1340dcb15..1e4869f8e41 100644 --- a/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt +++ b/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt @@ -1,8 +1,8 @@ package multiplatform +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest class BasicMultiplatformTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt index 6e85fe01a18..13431bd200a 100644 --- a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt +++ b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt @@ -1,14 +1,13 @@ package pageMerger -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.withDescendants import org.jetbrains.dokka.pages.* +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.RepeatedTest -import java.lang.IllegalArgumentException +import org.junit.jupiter.api.Test import kotlin.test.assertEquals class PageNodeMergerTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt b/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt index cf1332db552..4b02a84b5c6 100644 --- a/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt +++ b/plugins/base/src/test/kotlin/parsers/JavadocParserTest.kt @@ -1,21 +1,17 @@ package parsers -import com.jetbrains.rd.util.first import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.base.translators.psi.parsers.* import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.JavaClassReference import org.jetbrains.dokka.model.DEnum import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import utils.docs import utils.text -import kotlin.random.* -import kotlin.test.* +import kotlin.test.assertNotNull class JavadocParserTest : BaseAbstractTest() { @@ -98,7 +94,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -136,7 +132,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -171,7 +167,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -208,7 +204,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -242,7 +238,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -359,7 +355,7 @@ class JavadocParserTest : BaseAbstractTest() { testInline(source, configuration) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() assertEquals(expected, docs.children.first().root.children) } } @@ -384,7 +380,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -428,7 +424,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -462,7 +458,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root assertEquals( @@ -500,7 +496,7 @@ class JavadocParserTest : BaseAbstractTest() { documentablesTransformationStage = { module -> val functionWithSeeTag = module.packages.flatMap { it.classlikes }.flatMap { it.functions } .find { it.name == "getProperty" && it.parameters.count() == 1 } - val seeTag = functionWithSeeTag?.docs()?.firstIsInstanceOrNull() + val seeTag = functionWithSeeTag?.docs()?.filterIsInstance()?.firstOrNull() val expectedLinkDestinationDRI = DRI( packageName = "example", classNames = "Source", @@ -538,7 +534,7 @@ class JavadocParserTest : BaseAbstractTest() { documentablesTransformationStage = { module -> val functionWithSeeTag = module.packages.flatMap { it.classlikes }.flatMap { it.functions } .find { it.name == "getProperty" && it.parameters.size == 1 } - val seeTag = functionWithSeeTag?.docs()?.firstIsInstanceOrNull() + val seeTag = functionWithSeeTag?.docs()?.filterIsInstance()?.firstOrNull() val expectedLinkDestinationDRI = DRI( packageName = "example", classNames = "Source", @@ -578,7 +574,7 @@ class JavadocParserTest : BaseAbstractTest() { configuration, ) { documentablesCreationStage = { modules -> - val docs = modules.first().packages.first().classlikes.single().documentation.first().value + val docs = modules.first().packages.first().classlikes.single().documentation.values.first() val root = docs.children.first().root kotlin.test.assertEquals( @@ -591,26 +587,27 @@ class JavadocParserTest : BaseAbstractTest() { } } - @Test - fun `test isolated parsing is case sensitive`() { - // Ensure that it won't accidentally break - val values = JavadocTag.values().map { it.toString().toLowerCase() } - val withRandomizedCapitalization = values.map { - val result = buildString { - for (char in it) { - if (Random.nextBoolean()) { - append(char) - } else { - append(char.toLowerCase()) - } - } - } - if (result == it) result.toUpperCase() else result - } - - for ((index, value) in JavadocTag.values().withIndex()) { - assertEquals(value, JavadocTag.lowercaseValueOfOrNull(values[index])) - assertNull(JavadocTag.lowercaseValueOfOrNull(withRandomizedCapitalization[index])) - } - } + // TODO [beresnev] move to java-analysis +// @Test +// fun `test isolated parsing is case sensitive`() { +// // Ensure that it won't accidentally break +// val values = JavadocTag.values().map { it.toString().toLowerCase() } +// val withRandomizedCapitalization = values.map { +// val result = buildString { +// for (char in it) { +// if (Random.nextBoolean()) { +// append(char) +// } else { +// append(char.toLowerCase()) +// } +// } +// } +// if (result == it) result.toUpperCase() else result +// } +// +// for ((index, value) in JavadocTag.values().withIndex()) { +// assertEquals(value, JavadocTag.lowercaseValueOfOrNull(values[index])) +// assertNull(JavadocTag.lowercaseValueOfOrNull(withRandomizedCapitalization[index])) +// } +// } } diff --git a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt index 244163eca33..f69cf80f97b 100644 --- a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt @@ -3,7 +3,7 @@ package renderers.html import org.jetbrains.dokka.base.renderers.html.HtmlRenderer import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test -import renderers.* +import renderers.testPage import utils.Div import utils.P import utils.match diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 5632994000b..7afc978cde7 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -10,11 +10,9 @@ import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProviderFactory import org.jetbrains.dokka.testApi.context.MockContext import org.jsoup.Jsoup import org.jsoup.nodes.Element -import org.jsoup.nodes.Node -import org.jsoup.nodes.TextNode import renderers.RenderingOnlyTestBase -import utils.TestOutputWriter import testApi.testRunner.defaultSourceSet +import utils.TestOutputWriter import java.io.File abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { diff --git a/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt index a7a7bacf629..de9c36ae783 100644 --- a/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt @@ -3,9 +3,9 @@ package renderers.html import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin -import kotlin.test.assertEquals import utils.navigationHtml import utils.selectNavigationGrid +import kotlin.test.assertEquals class NavigationIconTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/renderers/html/NavigationTest.kt b/plugins/base/src/test/kotlin/renderers/html/NavigationTest.kt index 21b4ea3c089..75993e492c0 100644 --- a/plugins/base/src/test/kotlin/renderers/html/NavigationTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/NavigationTest.kt @@ -5,8 +5,8 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jsoup.nodes.Element import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin -import kotlin.test.assertEquals import utils.navigationHtml +import kotlin.test.assertEquals import kotlin.test.assertNull class NavigationTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/signatures/FunctionalTypeConstructorsSignatureTest.kt b/plugins/base/src/test/kotlin/signatures/FunctionalTypeConstructorsSignatureTest.kt index edb5089d5f2..c9787b67be9 100644 --- a/plugins/base/src/test/kotlin/signatures/FunctionalTypeConstructorsSignatureTest.kt +++ b/plugins/base/src/test/kotlin/signatures/FunctionalTypeConstructorsSignatureTest.kt @@ -1,15 +1,14 @@ package signatures import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.jdk import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.jdk import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import utils.A import utils.Span import utils.TestOutputWriterPlugin import utils.match -import java.lang.IllegalStateException class FunctionalTypeConstructorsSignatureTest : BaseAbstractTest() { private val configuration = dokkaConfiguration { diff --git a/plugins/base/src/test/kotlin/signatures/ObviousTypeSkippingTest.kt b/plugins/base/src/test/kotlin/signatures/ObviousTypeSkippingTest.kt index 5a6d95eb220..2837e891918 100644 --- a/plugins/base/src/test/kotlin/signatures/ObviousTypeSkippingTest.kt +++ b/plugins/base/src/test/kotlin/signatures/ObviousTypeSkippingTest.kt @@ -2,10 +2,10 @@ package signatures import matchers.content.assertNode import matchers.content.hasExactText +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.firstMemberOfType import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.testApi.logger.TestLogger -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.LoggingLevel import org.junit.jupiter.params.ParameterizedTest diff --git a/plugins/base/src/test/kotlin/signatures/VarianceSignatureTest.kt b/plugins/base/src/test/kotlin/signatures/VarianceSignatureTest.kt index b82b673c234..06a3daae26e 100644 --- a/plugins/base/src/test/kotlin/signatures/VarianceSignatureTest.kt +++ b/plugins/base/src/test/kotlin/signatures/VarianceSignatureTest.kt @@ -3,7 +3,6 @@ package signatures import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.jupiter.api.Test import utils.A -import utils.Span import utils.TestOutputWriterPlugin import utils.match diff --git a/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt index 5b97f9697fd..30fc127ff98 100644 --- a/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt +++ b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt @@ -1,10 +1,10 @@ package transformerBuilders import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.dfs +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.DokkaPluginApiPreview import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement import org.jetbrains.dokka.transformers.pages.PageTransformer @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin import utils.assertContains import utils.assertNotNull + class PageTransformerBuilderTest : BaseAbstractTest() { class ProxyPlugin(transformer: PageTransformer) : DokkaPlugin() { diff --git a/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt b/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt index 07dc0bc7202..e1029856eb6 100644 --- a/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt +++ b/plugins/base/src/test/kotlin/transformers/CommentsToContentConverterTest.kt @@ -5,7 +5,6 @@ import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConve import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.utils.addToStdlib.assertedCast import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -335,7 +334,7 @@ class CommentsToContentConverterTest { +"I'm an inline-style link" check { assertEquals( - assertedCast { "Link should be resolved" }.address, + (this as? ContentResolvedLink)?.address ?: error("Link should be resolved"), "https://www.google.com" ) } diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt index 8ed34b2a067..96de5c26dd6 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt @@ -1,13 +1,15 @@ package transformers import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.testApi.logger.TestLogger import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.LoggingLevel +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -81,11 +83,11 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd ) } - private val reader by lazy { ModuleAndPackageDocumentationReader(context) } + private val reader by lazy { context.plugin().querySingle { moduleAndPackageDocumentationReader } } @Test fun `assert moduleA with sourceSetA`() { - val documentation = reader[dModule(name = "moduleA", sourceSets = setOf(sourceSetA))] + val documentation = reader.read(dModule(name = "moduleA", sourceSets = setOf(sourceSetA))) assertEquals( 1, documentation.keys.size, "Expected moduleA only containing documentation in a single source set" @@ -103,7 +105,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with no source sets`() { - val documentation = reader[dModule("moduleA")] + val documentation = reader.read(dModule("moduleA")) assertEquals( emptyMap(), documentation, "Expected no documentation received for module not declaring a matching sourceSet" @@ -115,15 +117,15 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd assertThrows( "Expected no documentation received for module with unknown sourceSet" ) { - reader[ + reader.read( dModule("moduleA", sourceSets = setOf(configurationBuilder.unattachedSourceSet { name = "unknown" })) - ] + ) } } @Test fun `assert moduleA with all sourceSets`() { - val documentation = reader[dModule("moduleA", sourceSets = setOf(sourceSetA, sourceSetB, sourceSetB2))] + val documentation = reader.read(dModule("moduleA", sourceSets = setOf(sourceSetA, sourceSetB, sourceSetB2))) assertEquals(1, documentation.entries.size, "Expected only one entry from sourceSetA") assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") assertEquals("This is moduleA", documentation.texts.single()) @@ -131,7 +133,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleB with sourceSetB and sourceSetB2`() { - val documentation = reader[dModule("moduleB", sourceSets = setOf(sourceSetB, sourceSetB2))] + val documentation = reader.read(dModule("moduleB", sourceSets = setOf(sourceSetB, sourceSetB2))) assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is moduleB", documentation.texts.single()) @@ -139,7 +141,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_A in sourceSetA`() { - val documentation = reader[dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetA))] + val documentation = reader.read(dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetA))) assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetA") assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") assertEquals("This is package sample.a\\r\\n", documentation.texts.single()) @@ -147,7 +149,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_a_sub in sourceSetA`() { - val documentation = reader[dPackage(DRI("sample.a.sub"), sourceSets = setOf(sourceSetA))] + val documentation = reader.read(dPackage(DRI("sample.a.sub"), sourceSets = setOf(sourceSetA))) assertEquals( emptyMap(), documentation, "Expected no documentation found for different package" @@ -156,7 +158,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_a in sourceSetB`() { - val documentation = reader[dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetB))] + val documentation = reader.read(dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetB))) assertEquals( emptyMap(), documentation, "Expected no documentation found for different sourceSet" @@ -165,7 +167,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_b in sourceSetB`() { - val documentation = reader[dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB))] + val documentation = reader.read(dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB))) assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is package sample.b", documentation.texts.single()) @@ -173,7 +175,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_b in sourceSetB and sourceSetB2`() { - val documentation = reader[dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB, sourceSetB2))] + val documentation = reader.read(dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB, sourceSetB2))) assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is package sample.b", documentation.texts.single()) diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt index 609f808de61..d755668738e 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt @@ -1,10 +1,12 @@ package transformers -import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.LoggingLevel +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testApi.testRunner.TestDokkaConfigurationBuilder @@ -42,12 +44,12 @@ class ContextModuleAndPackageDocumentationReaderTest3 : AbstractContextModuleAnd ) } - private val reader by lazy { ModuleAndPackageDocumentationReader(context) } + private val reader by lazy { context.plugin().querySingle { moduleAndPackageDocumentationReader } } @Test fun `root package is matched by empty string and the root keyword`() { - val documentation = reader[dPackage(DRI(""), sourceSets = setOf(sourceSet))] + val documentation = reader.read(dPackage(DRI(""), sourceSets = setOf(sourceSet))) assertEquals( listOf("This is the root package", "This is also the root package"), documentation.texts ) diff --git a/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt b/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt index ef36d811a81..167985086c3 100644 --- a/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt +++ b/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt @@ -3,13 +3,12 @@ package transformers import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.PluginConfigurationImpl import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ContentHeader import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.ContentText -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -47,7 +46,7 @@ class DivisionSwitchTest : BaseAbstractTest() { } } suppressObviousFunctions = false - pluginsConfigurations.addIfNotNull( + pluginsConfigurations.add( PluginConfigurationImpl( DokkaBase::class.qualifiedName!!, DokkaConfiguration.SerializationFormat.JSON, @@ -120,4 +119,4 @@ class DivisionSwitchTest : BaseAbstractTest() { assertEquals(1, inheritedProperties.children.size, "Incorrect number of inherited properties found") } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/transformers/InvalidContentModuleAndPackageDocumentationReaderTest.kt b/plugins/base/src/test/kotlin/transformers/InvalidContentModuleAndPackageDocumentationReaderTest.kt index 59c83b7d9c3..20c5f912313 100644 --- a/plugins/base/src/test/kotlin/transformers/InvalidContentModuleAndPackageDocumentationReaderTest.kt +++ b/plugins/base/src/test/kotlin/transformers/InvalidContentModuleAndPackageDocumentationReaderTest.kt @@ -1,9 +1,11 @@ package transformers -import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.LoggingLevel +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testApi.testRunner.TestDokkaConfigurationBuilder @@ -65,14 +67,14 @@ class InvalidContentModuleAndPackageDocumentationReaderTest : AbstractContextMod ) } - private val readerA by lazy { ModuleAndPackageDocumentationReader(contextA) } - private val readerB by lazy { ModuleAndPackageDocumentationReader(contextB) } + private val readerA by lazy { contextA.plugin().querySingle { moduleAndPackageDocumentationReader } } + private val readerB by lazy { contextB.plugin().querySingle { moduleAndPackageDocumentationReader } } @Test fun `parsing should fail with a message when documentation is in not proper format`() { val exception = - runCatching { readerA[dModule(name = "moduleA", sourceSets = setOf(sourceSetA))] }.exceptionOrNull() + runCatching { readerA.read(dModule(name = "moduleA", sourceSets = setOf(sourceSetA))) }.exceptionOrNull() assertEquals( "Unexpected classifier: \"Invalid\", expected either \"Module\" or \"Package\". \n" + "For more information consult the specification: https://kotlinlang.org/docs/dokka-module-and-package-docs.html", @@ -83,7 +85,7 @@ class InvalidContentModuleAndPackageDocumentationReaderTest : AbstractContextMod @Test fun `parsing should fail with a message where it encountered error and why`() { val exception = - runCatching { readerB[dModule(name = "moduleB", sourceSets = setOf(sourceSetB))] }.exceptionOrNull()?.message!! + runCatching { readerB.read(dModule(name = "moduleB", sourceSets = setOf(sourceSetB))) }.exceptionOrNull()?.message!! //I don't want to assert whole message since it contains a path to a temporary folder assertTrue(exception.contains("Wrong AST Tree. Header does not contain expected content in ")) diff --git a/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt b/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt index 5e3352095db..bfb37708244 100644 --- a/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt +++ b/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt @@ -8,7 +8,6 @@ import org.jetbrains.dokka.model.childrenOfType import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.firstChildOfType import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.Test import utils.assertNotNull import kotlin.test.assertEquals @@ -39,7 +38,7 @@ class MergeImplicitExpectActualDeclarationsTest : BaseAbstractTest() { sourceRoots = listOf("src/jvmMain/kotlin/pageMerger/Test.kt") } } - pluginsConfigurations.addIfNotNull( + pluginsConfigurations.add( PluginConfigurationImpl( DokkaBase::class.qualifiedName!!, DokkaConfiguration.SerializationFormat.JSON, @@ -355,4 +354,4 @@ class MergeImplicitExpectActualDeclarationsTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt index 9f934f3f18c..bd29339c1ba 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt @@ -1,16 +1,21 @@ package transformers -import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.analysis.markdown.MARKDOWN_FILE_NAME import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationTransformer import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.DPackage import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.model.doc.CustomDocTag +import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Text +import org.jetbrains.kotlin.analysis.kotlin.ModuleAndPackageDocumentationReader import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import testApi.testRunner.dPackage -import testApi.testRunner.documentationNode import testApi.testRunner.sourceSet @@ -20,8 +25,9 @@ class ModuleAndPackageDocumentationTransformerUnitTest { fun `empty list of modules`() { val transformer = ModuleAndPackageDocumentationTransformer( object : ModuleAndPackageDocumentationReader { - override fun get(module: DModule): SourceSetDependent = throw NotImplementedError() - override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun read(module: DModule): SourceSetDependent = throw NotImplementedError() + override fun read(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode = throw NotImplementedError() } ) @@ -34,13 +40,13 @@ class ModuleAndPackageDocumentationTransformerUnitTest { fun `single module documentation`() { val transformer = ModuleAndPackageDocumentationTransformer( object : ModuleAndPackageDocumentationReader { - override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() - override fun get(module: DModule): SourceSetDependent { + override fun read(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun read(module: DModule): SourceSetDependent { return module.sourceSets.associateWith { sourceSet -> documentationNode("doc" + sourceSet.displayName) } } - + override fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode = throw NotImplementedError() } ) @@ -77,13 +83,14 @@ class ModuleAndPackageDocumentationTransformerUnitTest { fun `merges with already existing module documentation`() { val transformer = ModuleAndPackageDocumentationTransformer( object : ModuleAndPackageDocumentationReader { - override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() - override fun get(module: DModule): SourceSetDependent { + override fun read(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun read(module: DModule): SourceSetDependent { /* Only add documentation for first source set */ return module.sourceSets.take(1).associateWith { sourceSet -> documentationNode("doc" + sourceSet.displayName) } } + override fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode = throw NotImplementedError() } ) @@ -121,8 +128,8 @@ class ModuleAndPackageDocumentationTransformerUnitTest { fun `package documentation`() { val transformer = ModuleAndPackageDocumentationTransformer( object : ModuleAndPackageDocumentationReader { - override fun get(module: DModule): SourceSetDependent = emptyMap() - override fun get(pkg: DPackage): SourceSetDependent { + override fun read(module: DModule): SourceSetDependent = emptyMap() + override fun read(pkg: DPackage): SourceSetDependent { /* Only attach documentation to packages with 'attach' */ if ("attach" !in pkg.dri.packageName.orEmpty()) return emptyMap() /* Only attach documentation to two source sets */ @@ -130,6 +137,7 @@ class ModuleAndPackageDocumentationTransformerUnitTest { documentationNode("doc:${sourceSet.displayName}:${pkg.dri.packageName}") } } + override fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode = throw NotImplementedError() } ) @@ -239,4 +247,10 @@ class ModuleAndPackageDocumentationTransformerUnitTest { ) } + + private fun documentationNode(vararg texts: String): DocumentationNode { + return DocumentationNode( + texts.toList() + .map { Description(CustomDocTag(listOf(Text(it)), name = MARKDOWN_FILE_NAME)) }) + } } diff --git a/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt index 13e90f42d55..431abef5a01 100644 --- a/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt @@ -5,7 +5,7 @@ import org.jetbrains.dokka.DokkaDefaults import org.jetbrains.dokka.PackageOptionsImpl import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test diff --git a/plugins/base/src/test/kotlin/transformers/SourceLinkTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/SourceLinkTransformerTest.kt index 81b4db69101..325afe74477 100644 --- a/plugins/base/src/test/kotlin/transformers/SourceLinkTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/SourceLinkTransformerTest.kt @@ -2,12 +2,12 @@ package transformers import org.jetbrains.dokka.SourceLinkDefinitionImpl import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jsoup.nodes.Element import org.junit.jupiter.api.Test import signatures.renderedContent import utils.TestOutputWriterPlugin import java.net.URL import kotlin.test.assertEquals -import org.jsoup.nodes.Element class SourceLinkTransformerTest : BaseAbstractTest() { @@ -64,4 +64,4 @@ class SourceLinkTransformerTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/transformers/SuppressedByConfigurationDocumentableFilterTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/SuppressedByConfigurationDocumentableFilterTransformerTest.kt index 73f043bc218..a60609703cf 100644 --- a/plugins/base/src/test/kotlin/transformers/SuppressedByConfigurationDocumentableFilterTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/SuppressedByConfigurationDocumentableFilterTransformerTest.kt @@ -2,8 +2,8 @@ package transformers import org.jetbrains.dokka.DokkaDefaults import org.jetbrains.dokka.PackageOptionsImpl -import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.DRI import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertIterableEquals import org.junit.jupiter.api.Test diff --git a/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt b/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt index aeea194fa46..dee4bf7aaa8 100644 --- a/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt +++ b/plugins/base/src/test/kotlin/translators/AccessorMethodNamingTest.kt @@ -1,8 +1,9 @@ package translators -import org.junit.jupiter.api.Assertions.* import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.DProperty +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test /** @@ -115,4 +116,4 @@ class AccessorMethodNamingTest : BaseAbstractTest() { assertEquals(testsDone, properties.size) } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/translators/Bug1341.kt b/plugins/base/src/test/kotlin/translators/Bug1341.kt index a4b93a7e6ad..a8c9e3420ab 100644 --- a/plugins/base/src/test/kotlin/translators/Bug1341.kt +++ b/plugins/base/src/test/kotlin/translators/Bug1341.kt @@ -1,7 +1,7 @@ package translators -import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.links.DRI import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test diff --git a/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt b/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt index a940264a65c..a763cbd28e7 100644 --- a/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt +++ b/plugins/base/src/test/kotlin/translators/DefaultPsiToDocumentableTranslatorTest.kt @@ -1,7 +1,6 @@ package translators import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.PointingToDeclaration @@ -13,7 +12,6 @@ import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement import org.jetbrains.dokka.DokkaConfiguration.Visibility import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test -import utils.assertNotNull class DefaultPsiToDocumentableTranslatorTest : BaseAbstractTest() { val configuration = dokkaConfiguration { @@ -320,70 +318,71 @@ class DefaultPsiToDocumentableTranslatorTest : BaseAbstractTest() { } } - class OnlyPsiPlugin : DokkaPlugin() { - private val dokkaBase by lazy { plugin() } - - @Suppress("unused") - val psiOverrideDescriptorTranslator by extending { - (dokkaBase.psiToDocumentableTranslator - override dokkaBase.descriptorToDocumentableTranslator) - } - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = - PluginApiPreviewAcknowledgement - } - - // for Kotlin classes from DefaultPsiToDocumentableTranslator - @Test - fun `should resolve ultralight class`() { - val configurationWithNoJVM = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/main/java") - } - } - } - - testInline( - """ - |/src/main/java/example/Test.kt - |package example - | - |open class KotlinSubClass { - | fun kotlinSubclassFunction(bar: String): String { - | return "KotlinSubClass" - | } - |} - | - |/src/main/java/example/JavaLeafClass.java - |package example; - | - |public class JavaLeafClass extends KotlinSubClass { - | public String javaLeafClassFunction(String baz) { - | return "JavaLeafClass"; - | } - |} - """.trimMargin(), - configurationWithNoJVM, - pluginOverrides = listOf(OnlyPsiPlugin()) // suppress a descriptor translator because of psi and descriptor translators work in parallel - ) { - documentablesMergingStage = { module -> - val kotlinSubclassFunction = - module.packages.single().classlikes.find { it.name == "JavaLeafClass" }?.functions?.find { it.name == "kotlinSubclassFunction" } - .assertNotNull("kotlinSubclassFunction ") - - assertEquals( - "String", - (kotlinSubclassFunction.type as? TypeConstructor)?.dri?.classNames - ) - assertEquals( - "String", - (kotlinSubclassFunction.parameters.firstOrNull()?.type as? TypeConstructor)?.dri?.classNames - ) - } - } - } + // TODO [beresnev] fix +// class OnlyPsiPlugin : DokkaPlugin() { +// private val kotlinAnalysisPlugin by lazy { plugin() } +// +// @Suppress("unused") +// val psiOverrideDescriptorTranslator by extending { +// (plugin().psiToDocumentableTranslator +// override kotlinAnalysisPlugin.descriptorToDocumentableTranslator) +// } +// +// @OptIn(DokkaPluginApiPreview::class) +// override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = +// PluginApiPreviewAcknowledgement +// } +// +// // for Kotlin classes from DefaultPsiToDocumentableTranslator +// @Test +// fun `should resolve ultralight class`() { +// val configurationWithNoJVM = dokkaConfiguration { +// sourceSets { +// sourceSet { +// sourceRoots = listOf("src/main/java") +// } +// } +// } +// +// testInline( +// """ +// |/src/main/java/example/Test.kt +// |package example +// | +// |open class KotlinSubClass { +// | fun kotlinSubclassFunction(bar: String): String { +// | return "KotlinSubClass" +// | } +// |} +// | +// |/src/main/java/example/JavaLeafClass.java +// |package example; +// | +// |public class JavaLeafClass extends KotlinSubClass { +// | public String javaLeafClassFunction(String baz) { +// | return "JavaLeafClass"; +// | } +// |} +// """.trimMargin(), +// configurationWithNoJVM, +// pluginOverrides = listOf(OnlyPsiPlugin()) // suppress a descriptor translator because of psi and descriptor translators work in parallel +// ) { +// documentablesMergingStage = { module -> +// val kotlinSubclassFunction = +// module.packages.single().classlikes.find { it.name == "JavaLeafClass" }?.functions?.find { it.name == "kotlinSubclassFunction" } +// .assertNotNull("kotlinSubclassFunction ") +// +// assertEquals( +// "String", +// (kotlinSubclassFunction.type as? TypeConstructor)?.dri?.classNames +// ) +// assertEquals( +// "String", +// (kotlinSubclassFunction.parameters.firstOrNull()?.type as? TypeConstructor)?.dri?.classNames +// ) +// } +// } +// } @Test fun `should preserve regular functions that are named like getters, but are not getters`() { @@ -822,12 +821,12 @@ class DefaultPsiToDocumentableTranslatorTest : BaseAbstractTest() { configuration ) { documentablesMergingStage = { module -> - val kotlinEnum = module.packages.find { it.name == "test" } + val javaEnum = module.packages.find { it.name == "test" } ?.classlikes ?.single { it.name == "JavaEnum" } - checkNotNull(kotlinEnum) + checkNotNull(javaEnum) - val valueOfFunction = kotlinEnum.functions.single { it.name == "valueOf" } + val valueOfFunction = javaEnum.functions.single { it.name == "valueOf" } val expectedDocumentation = DocumentationNode(listOf( Description( diff --git a/plugins/base/src/test/kotlin/translators/ExternalDocumentablesTest.kt b/plugins/base/src/test/kotlin/translators/ExternalDocumentablesTest.kt index 011ae72974e..a3cd7a9e1a6 100644 --- a/plugins/base/src/test/kotlin/translators/ExternalDocumentablesTest.kt +++ b/plugins/base/src/test/kotlin/translators/ExternalDocumentablesTest.kt @@ -1,15 +1,13 @@ package translators -import com.intellij.openapi.application.PathManager -import kotlinx.coroutines.Job -import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.base.translators.descriptors.ExternalDocumentablesProvider import org.jetbrains.dokka.model.DClass import org.jetbrains.dokka.model.DInterface import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.utilities.cast +import org.jetbrains.kotlin.analysis.kotlin.ExternalDocumentablesProvider +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -36,7 +34,7 @@ class ExternalDocumentablesTest : BaseAbstractTest() { ) { lateinit var provider: ExternalDocumentablesProvider pluginsSetupStage = { - provider = it.plugin().querySingle { externalDocumentablesProvider } + provider = it.plugin().querySingle { externalDocumentablesProvider } } documentablesTransformationStage = { mod -> val entry = mod.packages.single().classlikes.single().cast().supertypes.entries.single() @@ -59,7 +57,10 @@ class ExternalDocumentablesTest : BaseAbstractTest() { @Test fun `external documentable from dependency`() { val coroutinesPath = - PathManager.getResourceRoot(Job::class.java, "/kotlinx/coroutines/Job.class") + ClassLoader.getSystemResource("kotlinx/coroutines/Job.class") + ?.file + ?.replace("file:", "") + ?.replaceAfter(".jar", "") val configuration = dokkaConfiguration { sourceSets { @@ -82,7 +83,7 @@ class ExternalDocumentablesTest : BaseAbstractTest() { ) { lateinit var provider: ExternalDocumentablesProvider pluginsSetupStage = { - provider = it.plugin().querySingle { externalDocumentablesProvider } + provider = it.plugin().querySingle { externalDocumentablesProvider } } documentablesTransformationStage = { mod -> val entry = mod.packages.single().classlikes.single().cast().supertypes.entries.single() @@ -124,7 +125,7 @@ class ExternalDocumentablesTest : BaseAbstractTest() { ) { lateinit var provider: ExternalDocumentablesProvider pluginsSetupStage = { - provider = it.plugin().querySingle { externalDocumentablesProvider } + provider = it.plugin().querySingle { externalDocumentablesProvider } } documentablesTransformationStage = { mod -> val entry = mod.packages.single().classlikes.single().cast().supertypes.entries.single() @@ -136,4 +137,4 @@ class ExternalDocumentablesTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt b/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt index d5d25dc71c9..7fc6b7fae43 100644 --- a/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt +++ b/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt @@ -1,11 +1,10 @@ package translators +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.model.doc.CustomDocTag import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.junit.Ignore import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -306,4 +305,4 @@ class JavadocInheritDocsTest : BaseAbstractTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt b/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt index 7510e5416b7..ba0d95d52ac 100644 --- a/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt +++ b/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt @@ -1,11 +1,10 @@ package translators +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.PointingToDeclaration import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.jetbrains.dokka.model.doc.Deprecated as DokkaDeprecatedTag @@ -89,7 +88,7 @@ class JavadocInheritedDocTagsTest : BaseAbstractTest() { fun `work with return`() { performTagsTest { module -> val function = module.findFunction("sample", "Subclass", "test") - val renderedTag = function.documentation.values.first().children.firstIsInstance() + val renderedTag = function.documentation.values.first().children.filterIsInstance().first() val expectedTag = Return( CustomDocTag( children = listOf( @@ -155,7 +154,7 @@ class JavadocInheritedDocTagsTest : BaseAbstractTest() { fun `work with deprecated`() { performTagsTest { module -> val function = module.findFunction("sample", "Subclass", "test") - val renderedTag = function.documentation.values.first().children.firstIsInstance() + val renderedTag = function.documentation.values.first().children.filterIsInstance().first() val expectedTag = DokkaDeprecatedTag( CustomDocTag( children = listOf( @@ -175,7 +174,7 @@ class JavadocInheritedDocTagsTest : BaseAbstractTest() { fun `work with see also`() { performTagsTest { module -> val function = module.findFunction("sample", "Subclass", "test") - val renderedTag = function.documentation.values.first().children.firstIsInstance() + val renderedTag = function.documentation.values.first().children.filterIsInstance().first() val expectedTag = See( CustomDocTag( children = listOf( @@ -197,7 +196,7 @@ class JavadocInheritedDocTagsTest : BaseAbstractTest() { fun `work with author`() { performTagsTest { module -> val classlike = module.findClasslike("sample", "Subclass") - val renderedTag = classlike.documentation.values.first().children.firstIsInstance() + val renderedTag = classlike.documentation.values.first().children.filterIsInstance().first() val expectedTag = Author( CustomDocTag( children = listOf( @@ -246,4 +245,4 @@ class JavadocInheritedDocTagsTest : BaseAbstractTest() { assertEquals(expectedXdTag, xdTag) } } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/translators/JavadocParserTest.kt b/plugins/base/src/test/kotlin/translators/JavadocParserTest.kt index 52902205f2f..2c1173c02c2 100644 --- a/plugins/base/src/test/kotlin/translators/JavadocParserTest.kt +++ b/plugins/base/src/test/kotlin/translators/JavadocParserTest.kt @@ -1,14 +1,14 @@ package translators +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.childrenOfType import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.firstChildOfType import org.jetbrains.dokka.model.firstMemberOfType -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import org.junit.jupiter.api.Assertions.* import utils.text class JavadocParserTest : BaseAbstractTest() { diff --git a/plugins/base/src/test/kotlin/translators/utils.kt b/plugins/base/src/test/kotlin/translators/utils.kt index f0522ade86c..f9049ee5837 100644 --- a/plugins/base/src/test/kotlin/translators/utils.kt +++ b/plugins/base/src/test/kotlin/translators/utils.kt @@ -3,7 +3,6 @@ package translators import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.Text -import java.util.NoSuchElementException fun DModule.documentationOf(className: String, functionName: String? = null): String = descriptionOf(className, functionName) diff --git a/plugins/base/src/test/kotlin/utils/contentUtils.kt b/plugins/base/src/test/kotlin/utils/contentUtils.kt index 4fce1155e9e..d741c2507a9 100644 --- a/plugins/base/src/test/kotlin/utils/contentUtils.kt +++ b/plugins/base/src/test/kotlin/utils/contentUtils.kt @@ -1,7 +1,10 @@ package utils import matchers.content.* -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.BasicTabbedContentType +import org.jetbrains.dokka.pages.ContentGroup +import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.RootPageNode //TODO: Try to unify those functions after update to 1.4 fun ContentMatcherBuilder<*>.functionSignature( @@ -328,4 +331,4 @@ data class ParamAttributes( ) fun RootPageNode.findTestType(packageName: String, name: String) = - children.single { it.name == packageName }.children.single { it.name == name } as ContentPage \ No newline at end of file + children.single { it.name == packageName }.children.single { it.name == name } as ContentPage diff --git a/plugins/gfm/build.gradle.kts b/plugins/gfm/build.gradle.kts index da64c0e9d30..b7e6fc181d0 100644 --- a/plugins/gfm/build.gradle.kts +++ b/plugins/gfm/build.gradle.kts @@ -7,20 +7,22 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) + implementation(projects.plugins.base) - testImplementation(projects.plugins.base) - testImplementation(projects.plugins.base.baseTestUtils) - implementation(libs.jackson.kotlin) - testImplementation(projects.core.testApi) - testImplementation(platform(libs.junit.bom)) - testImplementation(libs.junit.jupiter) + implementation(kotlin("reflect")) + implementation(libs.jackson.kotlin) constraints { implementation(libs.jackson.databind) { because("CVE-2022-42003") } } + + testImplementation(projects.plugins.base) + testImplementation(projects.plugins.base.baseTestUtils) + testImplementation(projects.core.testApi) + testImplementation(platform(libs.junit.bom)) + testImplementation(libs.junit.jupiter) } registerDokkaArtifactPublication("gfmPlugin") { diff --git a/plugins/gfm/gfm-template-processing/build.gradle.kts b/plugins/gfm/gfm-template-processing/build.gradle.kts index 021adae2ff3..9611a8aa3b6 100644 --- a/plugins/gfm/gfm-template-processing/build.gradle.kts +++ b/plugins/gfm/gfm-template-processing/build.gradle.kts @@ -8,12 +8,12 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) implementation(projects.plugins.base) implementation(projects.plugins.gfm) implementation(projects.plugins.allModulesPage) implementation(projects.plugins.templating) + implementation(kotlin("reflect")) implementation(libs.kotlinx.coroutines.core) testImplementation(projects.core.testApi) diff --git a/plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/gfmTemplating.kt b/plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/gfmTemplating.kt index e66f8a121cb..e286d9e53c5 100644 --- a/plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/gfmTemplating.kt +++ b/plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/gfmTemplating.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.gfm -import org.jetbrains.dokka.base.templating.toJsonString -import org.jetbrains.dokka.links.DRI import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.annotation.JsonTypeInfo.Id.CLASS +import org.jetbrains.dokka.base.templating.toJsonString +import org.jetbrains.dokka.links.DRI @JsonTypeInfo(use = CLASS) sealed class GfmCommand { diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/CodeWrappingTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/CodeWrappingTest.kt index a8b263eb176..ae40694cc62 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/CodeWrappingTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/CodeWrappingTest.kt @@ -1,10 +1,9 @@ package renderers.gfm import org.jetbrains.dokka.gfm.renderer.CommonmarkRenderer -import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test +import renderers.testPage import kotlin.test.assertEquals -import renderers.* class CodeWrappingTest : GfmRenderingOnlyTestBase() { @Test diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/GroupWrappingTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/GroupWrappingTest.kt index eafe3e13ddf..1d6a79ca6e0 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/GroupWrappingTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/GroupWrappingTest.kt @@ -3,7 +3,7 @@ package renderers.gfm import org.jetbrains.dokka.gfm.renderer.CommonmarkRenderer import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test -import renderers.* +import renderers.testPage class GroupWrappingTest : GfmRenderingOnlyTestBase() { diff --git a/plugins/javadoc/api/javadoc.api b/plugins/javadoc/api/javadoc.api index 4d077882203..ff2599e94af 100644 --- a/plugins/javadoc/api/javadoc.api +++ b/plugins/javadoc/api/javadoc.api @@ -583,13 +583,13 @@ public final class org/jetbrains/dokka/javadoc/pages/TitleNode : org/jetbrains/d } public final class org/jetbrains/dokka/javadoc/pages/TreeViewInstaller : org/jetbrains/dokka/transformers/pages/PageTransformer { - public static final field INSTANCE Lorg/jetbrains/dokka/javadoc/pages/TreeViewInstaller; + public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; } public final class org/jetbrains/dokka/javadoc/pages/TreeViewPage : org/jetbrains/dokka/javadoc/pages/JavadocPageNode { - public fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Lorg/jetbrains/dokka/pages/PageNode;)V - public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Lorg/jetbrains/dokka/pages/PageNode;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Lorg/jetbrains/dokka/pages/PageNode;Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceBuilder;)V + public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;Lorg/jetbrains/dokka/pages/PageNode;Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceBuilder;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun getChildren ()Ljava/util/List; public final fun getClasses ()Ljava/util/List; public fun getContent ()Lorg/jetbrains/dokka/pages/ContentNode; @@ -597,6 +597,7 @@ public final class org/jetbrains/dokka/javadoc/pages/TreeViewPage : org/jetbrain public fun getDocumentables ()Ljava/util/List; public fun getDri ()Ljava/util/Set; public fun getEmbeddedResources ()Ljava/util/List; + public final fun getInheritanceBuilder ()Lorg/jetbrains/kotlin/analysis/kotlin/InheritanceBuilder; public final fun getKind ()Ljava/lang/String; public fun getName ()Ljava/lang/String; public final fun getPackages ()Ljava/util/List; @@ -606,24 +607,6 @@ public final class org/jetbrains/dokka/javadoc/pages/TreeViewPage : org/jetbrain public fun modified (Ljava/lang/String;Lorg/jetbrains/dokka/pages/ContentNode;Ljava/util/Set;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/dokka/pages/ContentPage; } -public final class org/jetbrains/dokka/javadoc/pages/TreeViewPage$InheritanceNode { - public fun (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Z)V - public synthetic fun (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Lorg/jetbrains/dokka/links/DRI; - public final fun component2 ()Ljava/util/List; - public final fun component3 ()Ljava/util/List; - public final fun component4 ()Z - public final fun copy (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Z)Lorg/jetbrains/dokka/javadoc/pages/TreeViewPage$InheritanceNode; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/javadoc/pages/TreeViewPage$InheritanceNode;Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;ZILjava/lang/Object;)Lorg/jetbrains/dokka/javadoc/pages/TreeViewPage$InheritanceNode; - public fun equals (Ljava/lang/Object;)Z - public final fun getChildren ()Ljava/util/List; - public final fun getDri ()Lorg/jetbrains/dokka/links/DRI; - public final fun getInterfaces ()Ljava/util/List; - public fun hashCode ()I - public final fun isInterface ()Z - public fun toString ()Ljava/lang/String; -} - public abstract interface class org/jetbrains/dokka/javadoc/pages/WithBrief { public abstract fun getBrief ()Ljava/util/List; } diff --git a/plugins/javadoc/build.gradle.kts b/plugins/javadoc/build.gradle.kts index 462e966ff72..df3c648b80d 100644 --- a/plugins/javadoc/build.gradle.kts +++ b/plugins/javadoc/build.gradle.kts @@ -7,21 +7,19 @@ plugins { dependencies { compileOnly(projects.core) - compileOnly(projects.kotlinAnalysis) + compileOnly(projects.analysis.kotlinAnalysisApi) - implementation(kotlin("reflect")) - implementation(libs.soywiz.korte) implementation(projects.plugins.base) implementation(projects.plugins.kotlinAsJava) + implementation(kotlin("reflect")) + implementation(libs.soywiz.korte) implementation(libs.kotlinx.html) implementation(libs.kotlinx.coroutines.core) testImplementation(projects.plugins.base.baseTestUtils) testImplementation(projects.core.testApi) - testImplementation(libs.jsoup) - testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) } diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPlugin.kt index 50355c7e9aa..70362ad46d3 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPlugin.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPlugin.kt @@ -1,15 +1,15 @@ package org.jetbrains.dokka.javadoc -import org.jetbrains.dokka.javadoc.location.JavadocLocationProviderFactory -import org.jetbrains.dokka.javadoc.renderer.KorteJavadocRenderer -import org.jetbrains.dokka.javadoc.signatures.JavadocSignatureProvider import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.PackageListCreator import org.jetbrains.dokka.base.renderers.RootCreator import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.PACKAGE_LIST_NAME import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat +import org.jetbrains.dokka.javadoc.location.JavadocLocationProviderFactory import org.jetbrains.dokka.javadoc.pages.* +import org.jetbrains.dokka.javadoc.renderer.KorteJavadocRenderer +import org.jetbrains.dokka.javadoc.signatures.JavadocSignatureProvider import org.jetbrains.dokka.javadoc.transformers.documentables.JavadocDocumentableJVMSourceSetFilter import org.jetbrains.dokka.javadoc.validity.MultiplatformConfiguredChecker import org.jetbrains.dokka.kotlinAsJava.KotlinAsJavaPlugin @@ -70,7 +70,7 @@ class JavadocPlugin : DokkaPlugin() { } val treeViewInstaller by extending { - javadocPreprocessors with TreeViewInstaller order { after(rootCreator) } + javadocPreprocessors providing ::TreeViewInstaller order { after(rootCreator) } } val allClassessPageInstaller by extending { diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt index 8210b30af64..8c1f2510aa6 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt @@ -1,19 +1,14 @@ package org.jetbrains.dokka.javadoc.pages -import com.intellij.psi.PsiClass import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.DescriptorDocumentableSource -import org.jetbrains.dokka.analysis.PsiDocumentableSource -import org.jetbrains.dokka.analysis.from import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType +import org.jetbrains.kotlin.analysis.kotlin.InheritanceBuilder +import org.jetbrains.kotlin.analysis.kotlin.InheritanceNode interface JavadocPageNode : ContentPage, WithDocumentables @@ -386,7 +381,8 @@ class TreeViewPage( val classes: List?, override val dri: Set, override val documentables: List = emptyList(), - val root: PageNode + val root: PageNode, + val inheritanceBuilder: InheritanceBuilder ) : JavadocPageNode { init { assert(packages == null || classes == null) @@ -397,7 +393,6 @@ class TreeViewPage( getDocumentableEntries(node) }.groupBy({ it.first }) { it.second }.map { (l, r) -> l to r.first() }.toMap() - private val descriptorMap = getDescriptorMap() private val inheritanceTuple = generateInheritanceTree() internal val classGraph = inheritanceTuple.first internal val interfaceGraph = inheritanceTuple.second @@ -427,7 +422,8 @@ class TreeViewPage( classes = children.filterIsInstance().takeIf { it.isNotEmpty() }, dri = dri, documentables, - root = root + root = root, + inheritanceBuilder ) override fun modified(name: String, children: List): PageNode = @@ -437,7 +433,8 @@ class TreeViewPage( classes = children.filterIsInstance().takeIf { it.isNotEmpty() }, dri = dri, documentables, - root = root + root = root, + inheritanceBuilder ) override val embeddedResources: List = emptyList() @@ -484,51 +481,8 @@ class TreeViewPage( fun interfaceTree(node: InheritanceNode) = interfaceTreeRec(node).firstOrNull() // TODO.single() - fun gatherPsiClasses(psi: PsiClass): List>> = psi.supers.toList().let { l -> - listOf(psi to l) + l.flatMap { gatherPsiClasses(it) } - } - - val psiInheritanceTree = - childrenDocumentables.flatMap { (_, v) -> (v as? WithSources)?.sources?.values.orEmpty() } - .filterIsInstance().mapNotNull { it.psi as? PsiClass } - .flatMap(::gatherPsiClasses) - .flatMap { entry -> entry.second.map { it to entry.first } } - .let { - it + it.map { it.second to null } - } - .groupBy({ it.first }) { it.second } - .map { it.key to it.value.filterNotNull().distinct() } - .map { (k, v) -> - InheritanceNode( - DRI.from(k), - v.map { InheritanceNode(DRI.from(it)) }, - k.supers.filter { it.isInterface }.map { DRI.from(it) }, - k.isInterface - ) - - } - - val descriptorInheritanceTree = descriptorMap.flatMap { (_, v) -> - v.typeConstructor.supertypes - .map { getClassDescriptorForType(it) to v } - } - .let { - it + it.map { it.second to null } - } - .groupBy({ it.first }) { it.second } - .map { it.key to it.value.filterNotNull().distinct() } - .map { (k, v) -> - InheritanceNode( - DRI.from(k), - v.map { InheritanceNode(DRI.from(it)) }, - k.typeConstructor.supertypes.map { getClassDescriptorForType(it) } - .mapNotNull { cd -> cd.takeIf { it.kind == ClassKind.INTERFACE }?.let { DRI.from(it) } }, - isInterface = k.kind == ClassKind.INTERFACE - ) - } - - descriptorInheritanceTree.forEach { addToMap(it, mergeMap) } - psiInheritanceTree.forEach { addToMap(it, mergeMap) } + val inheritanceNodes = inheritanceBuilder.build(childrenDocumentables) + inheritanceNodes.forEach { addToMap(it, mergeMap) } val rootNodes = mergeMap.entries.filter { it.key.classNames in setOf("Any", "Object") //TODO: Probably should be matched by DRI, not just className @@ -539,47 +493,11 @@ class TreeViewPage( return rootNodes.let { Pair(it.mapNotNull(::classTree), it.mapNotNull(::interfaceTree)) } } - private fun generateInterfaceGraph() { - childrenDocumentables.values.filterIsInstance() - } - private fun getDocumentableEntries(node: WithDocumentables): List> = node.documentables.map { it.dri to it } + (node as? ContentPage)?.children?.filterIsInstance() ?.flatMap(::getDocumentableEntries).orEmpty() - private fun getDescriptorMap(): Map { - val map: MutableMap = mutableMapOf() - childrenDocumentables - .mapNotNull { (k, v) -> - v.descriptorForPlatform()?.let { k to it }?.also { (k, v) -> map[k] = v } - }.map { it.second }.forEach { gatherSupertypes(it, map) } - - return map.toMap() - } - - private fun gatherSupertypes(descriptor: ClassDescriptor, map: MutableMap) { - map.putIfAbsent(DRI.from(descriptor), descriptor) - descriptor.typeConstructor.supertypes.map { getClassDescriptorForType(it) } - .forEach { gatherSupertypes(it, map) } - } - - private fun Documentable?.descriptorForPlatform(platform: Platform = Platform.jvm) = - (this as? WithSources).descriptorForPlatform(platform) - - private fun WithSources?.descriptorForPlatform(platform: Platform = Platform.jvm) = this?.let { - it.sources.entries.find { it.key.analysisPlatform == platform }?.value?.let { it as? DescriptorDocumentableSource }?.descriptor as? ClassDescriptor - } - - data class InheritanceNode( - val dri: DRI, - val children: List = emptyList(), - val interfaces: List = emptyList(), - val isInterface: Boolean = false - ) { - override fun equals(other: Any?): Boolean = other is InheritanceNode && other.dri == dri - override fun hashCode(): Int = dri.hashCode() - } } private fun Documentable.kind(): String? = diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt index e6e0e03725e..5d1d72dfe42 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/htmlPreprocessors.kt @@ -8,7 +8,11 @@ import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.BooleanValue import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageTransformer +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin object ResourcesInstaller : PageTransformer { override fun invoke(input: RootPageNode): RootPageNode = input.modified( @@ -21,7 +25,7 @@ object ResourcesInstaller : PageTransformer { ) } -object TreeViewInstaller : PageTransformer { +class TreeViewInstaller(private val context: DokkaContext) : PageTransformer { override fun invoke(input: RootPageNode): RootPageNode = install(input, input) as RootPageNode private fun install(node: PageNode, root: RootPageNode): PageNode = when (node) { @@ -37,7 +41,8 @@ object TreeViewInstaller : PageTransformer { classes = null, dri = node.dri, documentables = node.documentables, - root = root + root = root, + inheritanceBuilder = context.plugin().querySingle { inheritanceBuilder } ) val nodeChildren = node.children.map { childNode -> @@ -56,7 +61,8 @@ object TreeViewInstaller : PageTransformer { classes = node.children.filterIsInstance(), dri = node.dri, documentables = node.documentables, - root = root + root = root, + inheritanceBuilder = context.plugin().querySingle { inheritanceBuilder } ) return node.modified(children = node.children + packageTree) as JavadocPackagePageNode @@ -180,4 +186,4 @@ object DeprecatedPageCreator : PageTransformer { ) ) } -} \ No newline at end of file +} diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt index 6a590bc7123..f345e32b3b2 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -1,16 +1,17 @@ package org.jetbrains.dokka.javadoc.renderer +import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider import org.jetbrains.dokka.javadoc.pages.* import org.jetbrains.dokka.javadoc.toNormalized -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.parent import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.ImplementedInterfaces import org.jetbrains.dokka.model.InheritedMember -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.utilities.formatToEndWithHtml import java.io.File diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt index f50ae124679..3a5daaa9a91 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/KorteJavadocRenderer.kt @@ -1,10 +1,6 @@ package org.jetbrains.dokka.javadoc.renderer import com.soywiz.korte.* -import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider -import org.jetbrains.dokka.javadoc.pages.* -import org.jetbrains.dokka.javadoc.renderer.JavadocContentToHtmlTranslator.Companion.buildLink -import org.jetbrains.dokka.javadoc.toNormalized import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -12,14 +8,21 @@ import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.OutputWriter import org.jetbrains.dokka.javadoc.JavadocPlugin +import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider +import org.jetbrains.dokka.javadoc.pages.* +import org.jetbrains.dokka.javadoc.renderer.JavadocContentToHtmlTranslator.Companion.buildLink +import org.jetbrains.dokka.javadoc.toNormalized import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.pages.RendererSpecificPage +import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.query import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.renderers.Renderer -import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.analysis.kotlin.InheritanceNode import java.time.LocalDate typealias TemplateMap = Map @@ -146,9 +149,9 @@ class KorteJavadocRenderer(val context: DokkaContext, resourceDir: String) : }, TeFunction("renderInheritanceGraph") { args -> @Suppress("UNCHECKED_CAST") - val rootNodes = args.first() as List + val rootNodes = args.first() as List - fun drawRec(node: TreeViewPage.InheritanceNode): String = + fun drawRec(node: InheritanceNode): String = "
  • " + node.dri.let { dri -> listOfNotNull( dri.packageName, @@ -170,8 +173,9 @@ class KorteJavadocRenderer(val context: DokkaContext, resourceDir: String) : }, Filter("length") { subject.dynamicLength() }, TeFunction("hasAnyDescription") { args -> - args.first().safeAs>>() - ?.any { it["description"]?.trim()?.isNotEmpty() ?: false } + @Suppress("UNCHECKED_CAST") + val map = args.first() as? List> + map?.any { it["description"]?.trim()?.isNotEmpty() ?: false } } ).forEach { when (it) { diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt index 6c2fed58ccc..a7a01fc1fc8 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/renderer/SearchScriptsCreator.kt @@ -1,16 +1,15 @@ package org.jetbrains.dokka.javadoc.renderer -import org.jetbrains.dokka.javadoc.pages.* -import org.jetbrains.dokka.javadoc.renderer.SearchRecord.Companion.allTypes import org.jetbrains.dokka.base.renderers.sourceSets -import org.jetbrains.dokka.base.resolvers.local.resolveOrThrow import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.base.resolvers.local.resolveOrThrow +import org.jetbrains.dokka.javadoc.pages.* +import org.jetbrains.dokka.javadoc.renderer.SearchRecord.Companion.allTypes import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.utilities.formatToEndWithHtml -import java.lang.StringBuilder class SearchScriptsCreator(private val locationProvider: LocationProvider) { diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/signatures/JavadocSignatureProvider.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/signatures/JavadocSignatureProvider.kt index 385e0986da6..f81b8c5c9eb 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/signatures/JavadocSignatureProvider.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/signatures/JavadocSignatureProvider.kt @@ -1,12 +1,12 @@ package org.jetbrains.dokka.javadoc.signatures -import org.jetbrains.dokka.javadoc.translators.documentables.JavadocPageContentBuilder import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.signatures.JvmSignatureUtils import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.javadoc.translators.documentables.JavadocPageContentBuilder import org.jetbrains.dokka.kotlinAsJava.signatures.JavaSignatureUtils import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.sureClassNames diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/translators/documentables/JavadocPageContentBuilder.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/translators/documentables/JavadocPageContentBuilder.kt index e70f837091b..68faba5f46d 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/translators/documentables/JavadocPageContentBuilder.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/translators/documentables/JavadocPageContentBuilder.kt @@ -1,16 +1,15 @@ package org.jetbrains.dokka.javadoc.translators.documentables -import org.jetbrains.dokka.javadoc.pages.JavadocSignatureContentNode import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.javadoc.pages.JavadocSignatureContentNode import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.utilities.DokkaLogger -import java.lang.IllegalStateException class JavadocPageContentBuilder( commentsConverter: CommentsToContentConverter, @@ -77,4 +76,4 @@ class JavadocPageContentBuilder( supertypes = supertypes ) } -} \ No newline at end of file +} diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt index 4d059d0e8fd..0e018b8e562 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/AbstractJavadocTemplateMapTest.kt @@ -1,14 +1,16 @@ package org.jetbrains.dokka.javadoc -import org.jetbrains.dokka.* +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfigurationImpl +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider import org.jetbrains.dokka.javadoc.pages.JavadocPageNode import org.jetbrains.dokka.javadoc.renderer.JavadocContentToTemplateMapTranslator -import org.jetbrains.dokka.javadoc.JavadocPlugin -import org.jetbrains.dokka.javadoc.location.JavadocLocationProvider +import org.jetbrains.dokka.jdk +import org.jetbrains.dokka.kotlinStdlib import org.jetbrains.dokka.model.withDescendants import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.* -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest internal abstract class AbstractJavadocTemplateMapTest : BaseAbstractTest() { protected var config: DokkaConfigurationImpl = dokkaConfiguration { diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt index 9f48b1db0fc..ca739ed371c 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/Asserts.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka.javadoc -import kotlin.contracts.* +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract // TODO replace with assertIs from kotlin-test as part of #2924 @OptIn(ExperimentalContracts::class) diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt index 907b032ba78..eca46421bd5 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/JavadocAccessorNamingTest.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.javadoc import org.jsoup.Jsoup -import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.assertEquals -import utils.* +import org.junit.jupiter.api.Test +import utils.TestOutputWriterPlugin internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() { @@ -77,4 +77,4 @@ internal class JavadocAccessorNamingTest : AbstractJavadocTemplateMapTest() { } } } -} \ No newline at end of file +} diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLinkingTest.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLinkingTest.kt index 87c5246d894..afb4f04cf75 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLinkingTest.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLinkingTest.kt @@ -1,11 +1,11 @@ package org.jetbrains.dokka.javadoc.location import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.jdk import org.jetbrains.dokka.kotlinStdlib import org.jetbrains.dokka.model.doc.DocumentationLink import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.utilities.cast import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationTest.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationTest.kt index f0e2b49d059..6f61f72b440 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationTest.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/location/JavadocLocationTest.kt @@ -1,19 +1,21 @@ package org.jetbrains.dokka.javadoc.location -import org.jetbrains.dokka.* +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.javadoc.JavadocPlugin import org.jetbrains.dokka.javadoc.pages.JavadocClasslikePageNode +import org.jetbrains.dokka.javadoc.pages.JavadocFunctionNode import org.jetbrains.dokka.javadoc.pages.JavadocPackagePageNode import org.jetbrains.dokka.javadoc.renderer.JavadocContentToHtmlTranslator -import org.jetbrains.dokka.javadoc.JavadocPlugin +import org.jetbrains.dokka.jdk +import org.jetbrains.dokka.kotlinStdlib import org.jetbrains.dokka.model.firstChildOfType import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.javadoc.pages.JavadocFunctionNode -import org.junit.jupiter.api.Test import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test class JavadocLocationTest : BaseAbstractTest() { diff --git a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/packagelist/JavadocPackageListTest.kt b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/packagelist/JavadocPackageListTest.kt index 89e4c53523f..1947fec7fb1 100644 --- a/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/packagelist/JavadocPackageListTest.kt +++ b/plugins/javadoc/src/test/kotlin/org/jetbrains/dokka/javadoc/packagelist/JavadocPackageListTest.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.javadoc.packagelist import org.jetbrains.dokka.javadoc.AbstractJavadocTemplateMapTest +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin -import org.junit.jupiter.api.Assertions.* internal class JavadocPackageListTest : AbstractJavadocTemplateMapTest() { @Test diff --git a/plugins/jekyll/build.gradle.kts b/plugins/jekyll/build.gradle.kts index ab99e220bec..ca8ad618e67 100644 --- a/plugins/jekyll/build.gradle.kts +++ b/plugins/jekyll/build.gradle.kts @@ -7,10 +7,12 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) + implementation(projects.plugins.base) implementation(projects.plugins.gfm) + implementation(kotlin("reflect")) + testImplementation(projects.core.testApi) testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) diff --git a/plugins/jekyll/jekyll-template-processing/build.gradle.kts b/plugins/jekyll/jekyll-template-processing/build.gradle.kts index 936c77bde37..d18b203efc3 100644 --- a/plugins/jekyll/jekyll-template-processing/build.gradle.kts +++ b/plugins/jekyll/jekyll-template-processing/build.gradle.kts @@ -7,7 +7,6 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) implementation(projects.plugins.base) implementation(projects.plugins.jekyll) @@ -16,6 +15,7 @@ dependencies { implementation(projects.plugins.gfm) implementation(projects.plugins.gfm.gfmTemplateProcessing) + implementation(kotlin("reflect")) implementation(libs.kotlinx.coroutines.core) testImplementation(projects.core.testApi) diff --git a/plugins/kotlin-as-java/api/kotlin-as-java.api b/plugins/kotlin-as-java/api/kotlin-as-java.api index 301e432e009..03fc79bf3a6 100644 --- a/plugins/kotlin-as-java/api/kotlin-as-java.api +++ b/plugins/kotlin-as-java/api/kotlin-as-java.api @@ -15,6 +15,10 @@ public final class org/jetbrains/dokka/kotlinAsJava/TransformToJavaKt { public static synthetic fun transformToJava$default (Lorg/jetbrains/dokka/model/DProperty;Lorg/jetbrains/dokka/plugability/DokkaContext;ZLjava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/model/DProperty; } +public final class org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter { + public fun (Lorg/jetbrains/dokka/plugability/DokkaContext;)V +} + public final class org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverterKt { public static final fun getJvmNameProvider ()Lorg/jetbrains/dokka/kotlinAsJava/transformers/JvmNameProvider; } @@ -93,7 +97,7 @@ public final class org/jetbrains/dokka/kotlinAsJava/translators/KotlinAsJavaDocu } public final class org/jetbrains/dokka/kotlinAsJava/translators/KotlinAsJavaPageCreator : org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator { - public fun (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;)V + public fun (Lorg/jetbrains/dokka/base/DokkaBaseConfiguration;Lorg/jetbrains/dokka/base/transformers/pages/comments/CommentsToContentConverter;Lorg/jetbrains/dokka/base/signatures/SignatureProvider;Lorg/jetbrains/dokka/utilities/DokkaLogger;Ljava/util/List;Lorg/jetbrains/kotlin/analysis/kotlin/DocumentableAnalyzer;)V public fun pageForProperty (Lorg/jetbrains/dokka/model/DProperty;)Lorg/jetbrains/dokka/pages/MemberPageNode; } diff --git a/plugins/kotlin-as-java/build.gradle.kts b/plugins/kotlin-as-java/build.gradle.kts index 471578db66f..d2efda1a9db 100644 --- a/plugins/kotlin-as-java/build.gradle.kts +++ b/plugins/kotlin-as-java/build.gradle.kts @@ -7,15 +7,16 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) - compileOnly(projects.kotlinAnalysis) + compileOnly(projects.analysis.kotlinAnalysisApi) + implementation(projects.plugins.base) + + implementation(kotlin("reflect")) + + testImplementation(libs.jsoup) testImplementation(projects.plugins.base) testImplementation(projects.plugins.base.baseTestUtils) testImplementation(projects.core.contentMatcherTestUtils) - testImplementation(libs.jsoup) - testImplementation(projects.kotlinAnalysis) - testImplementation(projects.core.testApi) testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) diff --git a/plugins/kotlin-as-java/src/main/kotlin/CollectionExtensions.kt b/plugins/kotlin-as-java/src/main/kotlin/CollectionExtensions.kt new file mode 100644 index 00000000000..77e4ab0af0e --- /dev/null +++ b/plugins/kotlin-as-java/src/main/kotlin/CollectionExtensions.kt @@ -0,0 +1,12 @@ +package org.jetbrains.dokka.kotlinAsJava + +// TODO [beresnev] remove this copy-paste and use the same method from stdlib instead after updating to 1.5 +internal inline fun Iterable.firstNotNullOfOrNull(transform: (T) -> R?): R? { + for (element in this) { + val result = transform(element) + if (result != null) { + return result + } + } + return null +} diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinCompanion.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinCompanion.kt index dec1591a18b..68ad1ecff9d 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinCompanion.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinCompanion.kt @@ -46,20 +46,11 @@ internal fun DObject.companionInstancePropertyForJava(): DProperty? { ) } -internal fun DObject.companionAsJava(): DObject? { - if (hasNothingToRender()) return null - - return asJava( - excludedProps = staticPropertiesForJava(), - excludedFunctions = staticFunctionsForJava() - ) -} - /** * Hide companion object if there isn't members of parents. * Properties and functions that are moved to outer class are not counted as members. */ -private fun DObject.hasNothingToRender(): Boolean { +internal fun DObject.hasNothingToRender(): Boolean { val nonStaticPropsCount = properties.size - staticPropertiesForJava().size val nonStaticFunctionsCount = functions.size - staticFunctionsForJava().size val classLikesCount = classlikes.size diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt index 4df0d3c5764..ed222240446 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt @@ -5,14 +5,13 @@ import org.jetbrains.dokka.kotlinAsJava.transformers.JvmNameProvider import org.jetbrains.dokka.kotlinAsJava.transformers.withCallableName import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.PointingToDeclaration import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin val jvmNameProvider = JvmNameProvider() internal const val OBJECT_INSTANCE_NAME = "INSTANCE" @@ -29,469 +28,477 @@ internal val DProperty.isJvmField: Boolean internal val DFunction.isJvmStatic: Boolean get() = jvmStatic() != null -internal fun DPackage.asJava(): DPackage { - val syntheticClasses = - (properties.map { jvmNameProvider.nameForSyntheticClass(it) to it } - + functions.map { jvmNameProvider.nameForSyntheticClass(it) to it }) - .groupBy({ it.first }) { it.second } - .map { (syntheticClassName, nodes) -> - DClass( - dri = dri.withClass(syntheticClassName.name), - name = syntheticClassName.name, - properties = nodes - .filterIsInstance() - .filterNot { it.hasJvmSynthetic() } - .map { it.asJava(true) }, - constructors = emptyList(), - functions = ( - nodes - .filterIsInstance() - .filterNot { it.isConst || it.isJvmField || it.hasJvmSynthetic() } - .flatMap { it.javaAccessors(relocateToClass = syntheticClassName.name) } + - nodes - .filterIsInstance() - .flatMap { it.asJava(syntheticClassName.name, true) }) - .filterNot { it.hasJvmSynthetic() }, - classlikes = emptyList(), - sources = emptyMap(), - expectPresentInSet = null, - visibility = sourceSets.associateWith { - JavaVisibility.Public - }, - companion = null, - generics = emptyList(), - supertypes = emptyMap(), - documentation = emptyMap(), - modifier = sourceSets.associateWith { JavaModifier.Final }, - sourceSets = sourceSets, - isExpectActual = false, - extra = PropertyContainer.empty() - ) - } +private fun DProperty.hasModifier(modifier: ExtraModifiers.KotlinOnlyModifiers): Boolean = + extra[AdditionalModifiers] + ?.content + ?.any { (_, modifiers) -> modifier in modifiers } == true - return copy( - functions = emptyList(), - properties = emptyList(), - classlikes = classlikes.map { it.asJava() } + syntheticClasses, - typealiases = emptyList() - ) -} +class KotlinToJavaConverter( + private val context: DokkaContext +) { + private val kotlinToJavaMapper by lazy { + context.plugin().querySingle { kotlinToJavaMapper } + } -internal fun DProperty.asJava( - isTopLevel: Boolean = false, - relocateToClass: String? = null, - isFromObjectOrCompanion: Boolean = false -) = - copy( - dri = if (relocateToClass.isNullOrBlank()) { - dri - } else { - dri.withClass(relocateToClass) - }, - modifier = javaModifierFromSetter(), - visibility = visibility.mapValues { - if (isConst || isJvmField || (getter == null && setter == null) || (isFromObjectOrCompanion && isLateInit)) { - it.value.asJava() - } else { - it.value.propertyVisibilityAsJava() - } - }, - type = type.asJava(), // TODO: check - setter = null, - getter = null, // Removing getters and setters as they will be available as functions - extra = if (isTopLevel || isConst || (isFromObjectOrCompanion && isJvmField) || (isFromObjectOrCompanion && isLateInit)) - extra + extra.mergeAdditionalModifiers( - sourceSets.associateWith { - setOf(ExtraModifiers.JavaOnlyModifiers.Static) + internal fun DPackage.asJava(): DPackage { + val syntheticClasses = + (properties.map { jvmNameProvider.nameForSyntheticClass(it) to it } + + functions.map { jvmNameProvider.nameForSyntheticClass(it) to it }) + .groupBy({ it.first }) { it.second } + .map { (syntheticClassName, nodes) -> + DClass( + dri = dri.withClass(syntheticClassName.name), + name = syntheticClassName.name, + properties = nodes + .filterIsInstance() + .filterNot { it.hasJvmSynthetic() } + .map { it.asJava(true) }, + constructors = emptyList(), + functions = ( + nodes + .filterIsInstance() + .filterNot { it.isConst || it.isJvmField || it.hasJvmSynthetic() } + .flatMap { it.javaAccessors(relocateToClass = syntheticClassName.name) } + + nodes + .filterIsInstance() + .flatMap { it.asJava(syntheticClassName.name, true) }) + .filterNot { it.hasJvmSynthetic() }, + classlikes = emptyList(), + sources = emptyMap(), + expectPresentInSet = null, + visibility = sourceSets.associateWith { + JavaVisibility.Public + }, + companion = null, + generics = emptyList(), + supertypes = emptyMap(), + documentation = emptyMap(), + modifier = sourceSets.associateWith { JavaModifier.Final }, + sourceSets = sourceSets, + isExpectActual = false, + extra = PropertyContainer.empty() + ) } - ) - else extra - ) -internal fun Visibility.asJava() = - when (this) { - is JavaVisibility -> this - is KotlinVisibility.Public, KotlinVisibility.Internal -> JavaVisibility.Public - is KotlinVisibility.Private -> JavaVisibility.Private - is KotlinVisibility.Protected -> JavaVisibility.Protected + return copy( + functions = emptyList(), + properties = emptyList(), + classlikes = classlikes.map { it.asJava() } + syntheticClasses, + typealiases = emptyList() + ) } -internal fun DProperty.javaModifierFromSetter() = - modifier.mapValues { - when { - it.value is JavaModifier -> it.value - setter == null -> JavaModifier.Final - else -> JavaModifier.Empty + internal fun DProperty.asJava( + isTopLevel: Boolean = false, + relocateToClass: String? = null, + isFromObjectOrCompanion: Boolean = false + ) = + copy( + dri = if (relocateToClass.isNullOrBlank()) { + dri + } else { + dri.withClass(relocateToClass) + }, + modifier = javaModifierFromSetter(), + visibility = visibility.mapValues { + if (isConst || isJvmField || (getter == null && setter == null) || (isFromObjectOrCompanion && isLateInit)) { + it.value.asJava() + } else { + it.value.propertyVisibilityAsJava() + } + }, + type = type.asJava(), // TODO: check + setter = null, + getter = null, // Removing getters and setters as they will be available as functions + extra = if (isTopLevel || isConst || (isFromObjectOrCompanion && isJvmField) || (isFromObjectOrCompanion && isLateInit)) + extra + extra.mergeAdditionalModifiers( + sourceSets.associateWith { + setOf(ExtraModifiers.JavaOnlyModifiers.Static) + } + ) + else extra + ) + + internal fun Visibility.asJava() = + when (this) { + is JavaVisibility -> this + is KotlinVisibility.Public, KotlinVisibility.Internal -> JavaVisibility.Public + is KotlinVisibility.Private -> JavaVisibility.Private + is KotlinVisibility.Protected -> JavaVisibility.Protected } - } -internal fun DProperty.javaAccessors(isTopLevel: Boolean = false, relocateToClass: String? = null): List = - listOfNotNull( - getter?.let { getter -> - val name = "get" + name.capitalize() - getter.copy( - dri = if (relocateToClass.isNullOrBlank()) { - getter.dri + internal fun DProperty.javaModifierFromSetter() = + modifier.mapValues { + when { + it.value is JavaModifier -> it.value + setter == null -> JavaModifier.Final + else -> JavaModifier.Empty + } + } + + internal fun DProperty.javaAccessors( + isTopLevel: Boolean = false, + relocateToClass: String? = null + ): List = + listOfNotNull( + getter?.let { getter -> + val name = "get" + name.capitalize() + getter.copy( + dri = if (relocateToClass.isNullOrBlank()) { + getter.dri + } else { + getter.dri.withClass(relocateToClass) + }.withCallableName(name), + name = name, + modifier = javaModifierFromSetter(), + visibility = visibility.mapValues { JavaVisibility.Public }, + type = getter.type.asJava(), + extra = if (isTopLevel) getter.extra + + getter.extra.mergeAdditionalModifiers( + sourceSets.associateWith { + setOf(ExtraModifiers.JavaOnlyModifiers.Static) + } + ) + else getter.extra + ) + }, + setter?.let { setter -> + val name = "set" + name.capitalize() + val baseDRI = (if (relocateToClass.isNullOrBlank()) { + setter.dri } else { - getter.dri.withClass(relocateToClass) - }.withCallableName(name), - name = name, - modifier = javaModifierFromSetter(), - visibility = visibility.mapValues { JavaVisibility.Public }, - type = getter.type.asJava(), - extra = if (isTopLevel) getter.extra + - getter.extra.mergeAdditionalModifiers( - sourceSets.associateWith { - setOf(ExtraModifiers.JavaOnlyModifiers.Static) - } + setter.dri.withClass(relocateToClass) + }).withCallableName(name) + setter.copy( + dri = baseDRI, + name = name, + parameters = setter.parameters.map { + it.copy( + dri = baseDRI.copy( + target = it.dri.target, + extra = it.dri.extra + ), type = it.type.asJava() ) - else getter.extra - ) - }, - setter?.let { setter -> - val name = "set" + name.capitalize() - val baseDRI = (if (relocateToClass.isNullOrBlank()) { - setter.dri - } else { - setter.dri.withClass(relocateToClass) - }).withCallableName(name) - setter.copy( - dri = baseDRI, - name = name, - parameters = setter.parameters.map { - it.copy( - dri = baseDRI.copy( - target = it.dri.target, - extra = it.dri.extra - ), type = it.type.asJava() + }, + modifier = javaModifierFromSetter(), + visibility = visibility.mapValues { JavaVisibility.Public }, + type = Void, + extra = if (isTopLevel) setter.extra + setter.extra.mergeAdditionalModifiers( + sourceSets.associateWith { + setOf(ExtraModifiers.JavaOnlyModifiers.Static) + } ) - }, - modifier = javaModifierFromSetter(), - visibility = visibility.mapValues { JavaVisibility.Public }, - type = Void, - extra = if (isTopLevel) setter.extra + setter.extra.mergeAdditionalModifiers( + else setter.extra + ) + } + ) + + private fun DFunction.asJava( + containingClassName: String, + newName: String, + parameters: List, + isTopLevel: Boolean = false + ): DFunction { + return copy( + dri = dri.copy(classNames = containingClassName, callable = dri.callable?.copy(name = newName)), + name = newName, + type = type.asJava(), + modifier = if (modifier.all { (_, v) -> v is KotlinModifier.Final } && isConstructor) + sourceSets.associateWith { JavaModifier.Empty } + else sourceSets.associateWith { modifier.values.first() }, + parameters = listOfNotNull(receiver?.asJava()) + parameters.map { it.asJava() }, + visibility = visibility.map { (sourceSet, visibility) -> Pair(sourceSet, visibility.asJava()) }.toMap(), + receiver = null, + extra = if (isTopLevel || isJvmStatic) { + extra + extra.mergeAdditionalModifiers( sourceSets.associateWith { setOf(ExtraModifiers.JavaOnlyModifiers.Static) } ) - else setter.extra - ) - } - ) + } else { + extra + } + ) + } -private fun DFunction.asJava( - containingClassName: String, - newName: String, - parameters: List, - isTopLevel: Boolean = false -): DFunction { - return copy( - dri = dri.copy(classNames = containingClassName, callable = dri.callable?.copy(name = newName)), - name = newName, - type = type.asJava(), - modifier = if (modifier.all { (_, v) -> v is KotlinModifier.Final } && isConstructor) - sourceSets.associateWith { JavaModifier.Empty } - else sourceSets.associateWith { modifier.values.first() }, - parameters = listOfNotNull(receiver?.asJava()) + parameters.map { it.asJava() }, - visibility = visibility.map { (sourceSet, visibility) -> Pair(sourceSet, visibility.asJava()) }.toMap(), - receiver = null, - extra = if (isTopLevel || isJvmStatic) { - extra + extra.mergeAdditionalModifiers( - sourceSets.associateWith { - setOf(ExtraModifiers.JavaOnlyModifiers.Static) - } - ) + private fun DFunction.withJvmOverloads( + containingClassName: String, + newName: String, + isTopLevel: Boolean = false + ): List? { + val (paramsWithDefaults, paramsWithoutDefaults) = parameters + .withIndex() + .partition { (_, p) -> p.extra[DefaultValue] != null } + return paramsWithDefaults + .runningFold(paramsWithoutDefaults) { acc, param -> (acc + param) } + .map { params -> + asJava( + containingClassName, + newName, + params + .sortedBy(IndexedValue::index) + .map { it.value }, + isTopLevel + ) + } + .reversed() + .takeIf { it.isNotEmpty() } + } + + internal fun DFunction.asJava(containingClassName: String, isTopLevel: Boolean = false): List { + val newName = when { + isConstructor -> containingClassName + else -> name + } + val baseFunction = asJava(containingClassName, newName, parameters, isTopLevel) + return if (hasJvmOverloads()) { + withJvmOverloads(containingClassName, newName, isTopLevel) ?: listOf(baseFunction) } else { - extra + listOf(baseFunction) } - ) -} + } -private fun DFunction.withJvmOverloads( - containingClassName: String, - newName: String, - isTopLevel: Boolean = false -): List? { - val (paramsWithDefaults, paramsWithoutDefaults) = parameters - .withIndex() - .partition { (_, p) -> p.extra[DefaultValue] != null } - return paramsWithDefaults - .runningFold(paramsWithoutDefaults) { acc, param -> (acc + param) } - .map { params -> - asJava( - containingClassName, - newName, - params - .sortedBy(IndexedValue::index) - .map { it.value }, - isTopLevel - ) - } - .reversed() - .takeIf { it.isNotEmpty() } -} + internal fun DClasslike.asJava(): DClasslike = when (this) { + is DClass -> asJava() + is DEnum -> asJava() + is DAnnotation -> asJava() + is DObject -> asJava() + is DInterface -> asJava() + else -> throw IllegalArgumentException("$this shouldn't be here") + } + + internal fun DClass.asJava(): DClass = copy( + constructors = constructors + .filterNot { it.hasJvmSynthetic() } + .flatMap { + it.asJava( + dri.classNames ?: name + ) + }, // name may not always be valid here, however classNames should always be not null + functions = functionsInJava(), + properties = propertiesInJava(), + classlikes = classlikesInJava(), + generics = generics.map { it.asJava() }, + companion = companion?.companionAsJava(), + supertypes = supertypes.mapValues { it.value.map { it.asJava() } }, + modifier = if (modifier.all { (_, v) -> v is KotlinModifier.Empty }) sourceSets.associateWith { JavaModifier.Final } + else sourceSets.associateWith { modifier.values.first() } + ) -internal fun DFunction.asJava(containingClassName: String, isTopLevel: Boolean = false): List { - val newName = when { - isConstructor -> containingClassName - else -> name + /** + * Companion objects requires some custom logic for rendering as Java. + * They are excluded from usual classlikes rendering and added after. + */ + internal fun DClass.classlikesInJava(): List { + val classlikes = classlikes + .filter { it.name != companion?.name } + .map { it.asJava() } + + val companionAsJava = companion?.companionAsJava() + return if (companionAsJava != null) classlikes.plus(companionAsJava) else classlikes } - val baseFunction = asJava(containingClassName, newName, parameters, isTopLevel) - return if (hasJvmOverloads()) { - withJvmOverloads(containingClassName, newName, isTopLevel) ?: listOf(baseFunction) - } else { - listOf(baseFunction) + + + internal fun DClass.functionsInJava(): List = + properties + .filter { !it.isJvmField && !it.hasJvmSynthetic() } + .flatMap { property -> listOfNotNull(property.getter, property.setter) } + .plus(functions) + .plus(companion.staticFunctionsForJava()) + .filterNot { it.hasJvmSynthetic() } + .flatMap { it.asJava(it.dri.classNames ?: it.name) } + + internal fun DClass.propertiesInJava(): List { + val propertiesFromCompanion = companion + .staticPropertiesForJava() + .filterNot { it.hasJvmSynthetic() } + .map { it.asJava(isFromObjectOrCompanion = true) } + val companionInstanceProperty = companion?.companionInstancePropertyForJava() + val ownProperties = properties + .filterNot { it.hasJvmSynthetic() } + .map { it.asJava() } + + return propertiesFromCompanion + ownProperties + listOfNotNull(companionInstanceProperty) } -} -internal fun DClasslike.asJava(): DClasslike = when (this) { - is DClass -> asJava() - is DEnum -> asJava() - is DAnnotation -> asJava() - is DObject -> asJava() - is DInterface -> asJava() - else -> throw IllegalArgumentException("$this shouldn't be here") -} + private fun DTypeParameter.asJava(): DTypeParameter = copy( + variantTypeParameter = variantTypeParameter.withDri(dri.possiblyAsJava()), + bounds = bounds.map { it.asJava() } + ) -internal fun DClass.asJava(): DClass = copy( - constructors = constructors - .filterNot { it.hasJvmSynthetic() } - .flatMap { - it.asJava( - dri.classNames ?: name - ) - }, // name may not always be valid here, however classNames should always be not null - functions = functionsInJava(), - properties = propertiesInJava(), - classlikes = classlikesInJava(), - generics = generics.map { it.asJava() }, - companion = companion?.companionAsJava(), - supertypes = supertypes.mapValues { it.value.map { it.asJava() } }, - modifier = if (modifier.all { (_, v) -> v is KotlinModifier.Empty }) sourceSets.associateWith { JavaModifier.Final } - else sourceSets.associateWith { modifier.values.first() } -) - -/** - * Companion objects requires some custom logic for rendering as Java. - * They are excluded from usual classlikes rendering and added after. - */ -internal fun DClass.classlikesInJava(): List { - val classlikes = classlikes - .filter { it.name != companion?.name } - .map { it.asJava() } - - val companionAsJava = companion?.companionAsJava() - return if (companionAsJava != null) classlikes.plus(companionAsJava) else classlikes -} + private fun Projection.asJava(): Projection = when (this) { + is Star -> Star + is Covariance<*> -> copy(inner.asJava()) + is Contravariance<*> -> copy(inner.asJava()) + is Invariance<*> -> copy(inner.asJava()) + is Bound -> asJava() + } + private fun Bound.asJava(): Bound = when (this) { + is TypeParameter -> copy(dri.possiblyAsJava()) + is GenericTypeConstructor -> copy( + dri = dri.possiblyAsJava(), + projections = projections.map { it.asJava() } + ) -internal fun DClass.functionsInJava(): List = - properties - .filter { !it.isJvmField && !it.hasJvmSynthetic() } - .flatMap { property -> listOfNotNull(property.getter, property.setter) } - .plus(functions) - .plus(companion.staticFunctionsForJava()) - .filterNot { it.hasJvmSynthetic() } - .flatMap { it.asJava(it.dri.classNames ?: it.name) } - -internal fun DClass.propertiesInJava(): List { - val propertiesFromCompanion = companion - .staticPropertiesForJava() - .filterNot { it.hasJvmSynthetic() } - .map { it.asJava(isFromObjectOrCompanion = true) } - val companionInstanceProperty = companion?.companionInstancePropertyForJava() - val ownProperties = properties - .filterNot { it.hasJvmSynthetic() } - .map { it.asJava() } - - return propertiesFromCompanion + ownProperties + listOfNotNull(companionInstanceProperty) -} + is FunctionalTypeConstructor -> copy( + dri = dri.possiblyAsJava(), + projections = projections.map { it.asJava() } + ) -private fun DTypeParameter.asJava(): DTypeParameter = copy( - variantTypeParameter = variantTypeParameter.withDri(dri.possiblyAsJava()), - bounds = bounds.map { it.asJava() } -) - -private fun Projection.asJava(): Projection = when (this) { - is Star -> Star - is Covariance<*> -> copy(inner.asJava()) - is Contravariance<*> -> copy(inner.asJava()) - is Invariance<*> -> copy(inner.asJava()) - is Bound -> asJava() -} + is TypeAliased -> copy( + typeAlias = typeAlias.asJava(), + inner = inner.asJava() + ) + + is Nullable -> copy(inner.asJava()) + is DefinitelyNonNullable -> copy(inner.asJava()) + is PrimitiveJavaType -> this + is Void -> this + is JavaObject -> this + is Dynamic -> this + is UnresolvedBound -> this + } -private fun Bound.asJava(): Bound = when (this) { - is TypeParameter -> copy(dri.possiblyAsJava()) - is GenericTypeConstructor -> copy( - dri = dri.possiblyAsJava(), - projections = projections.map { it.asJava() } + internal fun DEnum.asJava(): DEnum = copy( + constructors = constructors.flatMap { it.asJava(dri.classNames ?: name) }, + functions = functions + .plus( + properties + .filter { !it.isJvmField && !it.hasJvmSynthetic() } + .flatMap { listOf(it.getter, it.setter) } + ) + .filterNotNull() + .filterNot { it.hasJvmSynthetic() } + .flatMap { it.asJava(dri.classNames ?: name) }, + properties = properties + .filterNot { it.hasJvmSynthetic() } + .map { it.asJava() }, + classlikes = classlikes.map { it.asJava() }, + supertypes = supertypes.mapValues { it.value.map { it.asJava() } } +// , entries = entries.map { it.asJava() } ) - is FunctionalTypeConstructor -> copy( - dri = dri.possiblyAsJava(), - projections = projections.map { it.asJava() } + + /** + * Parameters [excludedProps] and [excludedFunctions] used for rendering companion objects + * where some members (that lifted to outer class) are not rendered + */ + internal fun DObject.asJava( + excludedProps: List = emptyList(), + excludedFunctions: List = emptyList() + ): DObject = copy( + functions = functions + .plus( + properties + .filterNot { it in excludedProps } + .filter { !it.isJvmField && !it.isConst && !it.isLateInit && !it.hasJvmSynthetic() } + .flatMap { listOf(it.getter, it.setter) } + ) + .filterNotNull() + .filterNot { it in excludedFunctions } + .filterNot { it.hasJvmSynthetic() } + .flatMap { it.asJava(dri.classNames ?: name.orEmpty()) }, + properties = properties + .filterNot { it.hasJvmSynthetic() } + .filterNot { it in excludedProps } + .map { it.asJava(isFromObjectOrCompanion = true) } + + DProperty( + name = OBJECT_INSTANCE_NAME, + modifier = sourceSets.associateWith { JavaModifier.Final }, + dri = dri.copy(callable = Callable(OBJECT_INSTANCE_NAME, null, emptyList())), + documentation = emptyMap(), + sources = emptyMap(), + visibility = sourceSets.associateWith { + JavaVisibility.Public + }, + type = GenericTypeConstructor(dri, emptyList()), + setter = null, + getter = null, + sourceSets = sourceSets, + receiver = null, + generics = emptyList(), + expectPresentInSet = expectPresentInSet, + isExpectActual = false, + extra = PropertyContainer.withAll(sourceSets.map { + mapOf(it to setOf(ExtraModifiers.JavaOnlyModifiers.Static)).toAdditionalModifiers() + }) + ), + classlikes = classlikes.map { it.asJava() }, + supertypes = supertypes.mapValues { it.value.map { it.asJava() } } ) - is TypeAliased -> copy( - typeAlias = typeAlias.asJava(), - inner = inner.asJava() + + internal fun DInterface.asJava(): DInterface = copy( + functions = functions + .plus( + properties + .filter { it.jvmField() == null && !it.hasJvmSynthetic() } + .flatMap { listOf(it.getter, it.setter) } + ) + .filterNotNull() + .filterNot { it.hasJvmSynthetic() } + .flatMap { it.asJava(dri.classNames ?: name) }, + properties = emptyList(), + classlikes = classlikes.map { it.asJava() }, // TODO: public static final class DefaultImpls with impls for methods + generics = generics.map { it.asJava() }, + supertypes = supertypes.mapValues { it.value.map { it.asJava() } } ) - is Nullable -> copy(inner.asJava()) - is DefinitelyNonNullable -> copy(inner.asJava()) - is PrimitiveJavaType -> this - is Void -> this - is JavaObject -> this - is Dynamic -> this - is UnresolvedBound -> this -} -internal fun DEnum.asJava(): DEnum = copy( - constructors = constructors.flatMap { it.asJava(dri.classNames ?: name) }, - functions = functions - .plus( - properties - .filter { !it.isJvmField && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } - ) - .filterNotNull() - .filterNot { it.hasJvmSynthetic() } - .flatMap { it.asJava(dri.classNames ?: name) }, - properties = properties - .filterNot { it.hasJvmSynthetic() } - .map { it.asJava() }, - classlikes = classlikes.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.asJava() } } -// , entries = entries.map { it.asJava() } -) - -/** - * Parameters [excludedProps] and [excludedFunctions] used for rendering companion objects - * where some members (that lifted to outer class) are not rendered - */ -internal fun DObject.asJava( - excludedProps: List = emptyList(), - excludedFunctions: List = emptyList() -): DObject = copy( - functions = functions - .plus( - properties - .filterNot { it in excludedProps } - .filter { !it.isJvmField && !it.isConst && !it.isLateInit && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } - ) - .filterNotNull() - .filterNot { it in excludedFunctions } - .filterNot { it.hasJvmSynthetic() } - .flatMap { it.asJava(dri.classNames ?: name.orEmpty()) }, - properties = properties - .filterNot { it.hasJvmSynthetic() } - .filterNot { it in excludedProps } - .map { it.asJava(isFromObjectOrCompanion = true) } + - DProperty( - name = OBJECT_INSTANCE_NAME, - modifier = sourceSets.associateWith { JavaModifier.Final }, - dri = dri.copy(callable = Callable(OBJECT_INSTANCE_NAME, null, emptyList())), - documentation = emptyMap(), - sources = emptyMap(), - visibility = sourceSets.associateWith { - JavaVisibility.Public - }, - type = GenericTypeConstructor(dri, emptyList()), - setter = null, - getter = null, - sourceSets = sourceSets, - receiver = null, - generics = emptyList(), - expectPresentInSet = expectPresentInSet, - isExpectActual = false, - extra = PropertyContainer.withAll(sourceSets.map { - mapOf(it to setOf(ExtraModifiers.JavaOnlyModifiers.Static)).toAdditionalModifiers() - }) - ), - classlikes = classlikes.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.asJava() } } -) - -internal fun DInterface.asJava(): DInterface = copy( - functions = functions - .plus( - properties - .filter { it.jvmField() == null && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } - ) - .filterNotNull() - .filterNot { it.hasJvmSynthetic() } - .flatMap { it.asJava(dri.classNames ?: name) }, - properties = emptyList(), - classlikes = classlikes.map { it.asJava() }, // TODO: public static final class DefaultImpls with impls for methods - generics = generics.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.asJava() } } -) - -internal fun DAnnotation.asJava(): DAnnotation = copy( - properties = properties.map { it.asJava() }, - constructors = emptyList(), - classlikes = classlikes.map { it.asJava() } -) // TODO investigate if annotation class can have methods and properties not from constructor - -internal fun DParameter.asJava(): DParameter = copy( - type = type.asJava(), - name = if (name.isNullOrBlank()) "\$self" else name -) - -internal fun Visibility.propertyVisibilityAsJava(): Visibility = - if (this is JavaVisibility) this - else JavaVisibility.Private - -internal fun String.getAsPrimitive(): JvmPrimitiveType? = org.jetbrains.kotlin.builtins.PrimitiveType.values() - .find { it.typeFqName.asString() == this } - ?.let { JvmPrimitiveType.get(it) } - -private fun DRI.partialFqName() = packageName?.let { "$it." } + classNames -private fun DRI.possiblyAsJava() = this.partialFqName().mapToJava()?.toDRI(this) ?: this -private fun TypeConstructor.possiblyAsJava(): TypeConstructor = when (this) { - is GenericTypeConstructor -> copy(dri = this.dri.possiblyAsJava()) - is FunctionalTypeConstructor -> copy(dri = this.dri.possiblyAsJava()) -} + internal fun DAnnotation.asJava(): DAnnotation = copy( + properties = properties.map { it.asJava() }, + constructors = emptyList(), + classlikes = classlikes.map { it.asJava() } + ) // TODO investigate if annotation class can have methods and properties not from constructor -private fun String.mapToJava(): ClassId? = - JavaToKotlinClassMap.mapKotlinToJava(FqName(this).toUnsafe()) - -internal fun ClassId.toDRI(dri: DRI?): DRI = DRI( - packageName = packageFqName.asString(), - classNames = classNames(), - callable = dri?.callable,//?.asJava(), TODO: check this - extra = null, - target = PointingToDeclaration -) - -internal fun TypeConstructorWithKind.asJava(): TypeConstructorWithKind = - TypeConstructorWithKind( - typeConstructor = typeConstructor.possiblyAsJava(), - kind = kind.asJava() + internal fun DParameter.asJava(): DParameter = copy( + type = type.asJava(), + name = if (name.isNullOrBlank()) "\$self" else name ) -internal fun ClassKind.asJava(): ClassKind { - return when (this) { - is JavaClassKindTypes -> this - KotlinClassKindTypes.CLASS -> JavaClassKindTypes.CLASS - KotlinClassKindTypes.INTERFACE -> JavaClassKindTypes.INTERFACE - KotlinClassKindTypes.ENUM_CLASS -> JavaClassKindTypes.ENUM_CLASS - KotlinClassKindTypes.ENUM_ENTRY -> JavaClassKindTypes.ENUM_ENTRY - KotlinClassKindTypes.ANNOTATION_CLASS -> JavaClassKindTypes.ANNOTATION_CLASS - KotlinClassKindTypes.OBJECT -> JavaClassKindTypes.CLASS - else -> throw IllegalStateException("Non exchaustive match while trying to convert $this to Java") + internal fun Visibility.propertyVisibilityAsJava(): Visibility = + if (this is JavaVisibility) this + else JavaVisibility.Private + + private fun TypeConstructor.possiblyAsJava(): TypeConstructor = when (this) { + is GenericTypeConstructor -> copy(dri = this.dri.possiblyAsJava()) + is FunctionalTypeConstructor -> copy(dri = this.dri.possiblyAsJava()) } -} -private fun PropertyContainer.mergeAdditionalModifiers(second: SourceSetDependent>) = - this[AdditionalModifiers]?.squash(AdditionalModifiers(second)) ?: AdditionalModifiers(second) -private fun AdditionalModifiers.squash(second: AdditionalModifiers) = - AdditionalModifiers(content + second.content) + internal fun TypeConstructorWithKind.asJava(): TypeConstructorWithKind = + TypeConstructorWithKind( + typeConstructor = typeConstructor.possiblyAsJava(), + kind = kind.asJava() + ) -internal fun ClassId.classNames(): String = - shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "") + internal fun ClassKind.asJava(): ClassKind { + return when (this) { + is JavaClassKindTypes -> this + KotlinClassKindTypes.CLASS -> JavaClassKindTypes.CLASS + KotlinClassKindTypes.INTERFACE -> JavaClassKindTypes.INTERFACE + KotlinClassKindTypes.ENUM_CLASS -> JavaClassKindTypes.ENUM_CLASS + KotlinClassKindTypes.ENUM_ENTRY -> JavaClassKindTypes.ENUM_ENTRY + KotlinClassKindTypes.ANNOTATION_CLASS -> JavaClassKindTypes.ANNOTATION_CLASS + KotlinClassKindTypes.OBJECT -> JavaClassKindTypes.CLASS + else -> throw IllegalStateException("Non exchaustive match while trying to convert $this to Java") + } + } -private fun DProperty.hasModifier(modifier: ExtraModifiers.KotlinOnlyModifiers): Boolean = - extra[AdditionalModifiers] - ?.content - ?.any { (_, modifiers) -> modifier in modifiers } == true + private fun PropertyContainer.mergeAdditionalModifiers(second: SourceSetDependent>) = + this[AdditionalModifiers]?.squash(AdditionalModifiers(second)) ?: AdditionalModifiers(second) + + private fun AdditionalModifiers.squash(second: AdditionalModifiers) = + AdditionalModifiers(content + second.content) + + internal fun DObject.companionAsJava(): DObject? { + if (hasNothingToRender()) return null + + return asJava( + excludedProps = staticPropertiesForJava(), + excludedFunctions = staticFunctionsForJava() + ) + } + + private fun DRI.possiblyAsJava(): DRI { + return kotlinToJavaMapper.findAsJava(this) ?: this + } +} diff --git a/plugins/kotlin-as-java/src/main/kotlin/jvmField.kt b/plugins/kotlin-as-java/src/main/kotlin/jvmField.kt index fea78abbafd..8dc7bdb1160 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/jvmField.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/jvmField.kt @@ -3,10 +3,10 @@ package org.jetbrains.dokka.kotlinAsJava import org.jetbrains.dokka.model.Annotations import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.kotlin.util.firstNotNullResult internal fun WithExtraProperties.jvmField(): Annotations.Annotation? = - extra[Annotations]?.directAnnotations?.entries?.firstNotNullResult { (_, annotations) -> annotations.jvmFieldAnnotation() } + extra[Annotations]?.directAnnotations?.entries?.firstNotNullOfOrNull { (_, annotations) -> annotations.jvmFieldAnnotation() } internal fun List.jvmFieldAnnotation(): Annotations.Annotation? = firstOrNull { it.dri.packageName == "kotlin.jvm" && it.dri.classNames == "JvmField" } + diff --git a/plugins/kotlin-as-java/src/main/kotlin/jvmName.kt b/plugins/kotlin-as-java/src/main/kotlin/jvmName.kt index 600318e5d1a..8eed96e0027 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/jvmName.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/jvmName.kt @@ -5,15 +5,15 @@ import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.StringValue import org.jetbrains.dokka.model.isJvmName import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.kotlin.util.firstNotNullResult internal fun WithExtraProperties.directlyAnnotatedJvmName(): Annotations.Annotation? = - extra[Annotations]?.directAnnotations?.entries?.firstNotNullResult { (_, annotations)-> annotations.jvmNameAnnotation() } + extra[Annotations]?.directAnnotations?.entries?.firstNotNullOfOrNull { (_, annotations)-> annotations.jvmNameAnnotation() } internal fun WithExtraProperties.fileLevelJvmName(): Annotations.Annotation? = - extra[Annotations]?.fileLevelAnnotations?.entries?.firstNotNullResult { (_, annotations) -> annotations.jvmNameAnnotation() } + extra[Annotations]?.fileLevelAnnotations?.entries?.firstNotNullOfOrNull { (_, annotations) -> annotations.jvmNameAnnotation() } internal fun List.jvmNameAnnotation(): Annotations.Annotation? = firstOrNull { it.isJvmName() } internal fun Annotations.Annotation.jvmNameAsString(): String? = (params["name"] as? StringValue)?.value + diff --git a/plugins/kotlin-as-java/src/main/kotlin/jvmStatic.kt b/plugins/kotlin-as-java/src/main/kotlin/jvmStatic.kt index 50ea77957d1..82aac734282 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/jvmStatic.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/jvmStatic.kt @@ -3,10 +3,10 @@ package org.jetbrains.dokka.kotlinAsJava import org.jetbrains.dokka.model.Annotations import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.kotlin.util.firstNotNullResult internal fun WithExtraProperties.jvmStatic(): Annotations.Annotation? = - extra[Annotations]?.directAnnotations?.entries?.firstNotNullResult { (_, annotations) -> annotations.jvmStaticAnnotation() } + extra[Annotations]?.directAnnotations?.entries?.firstNotNullOfOrNull { (_, annotations) -> annotations.jvmStaticAnnotation() } internal fun List.jvmStaticAnnotation(): Annotations.Annotation? = firstOrNull { it.dri.packageName == "kotlin.jvm" && it.dri.classNames == "JvmStatic" } + diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index 05442b544bf..e51b31cb3e6 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -8,7 +8,10 @@ import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.ContentKind +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.TextStyle +import org.jetbrains.dokka.pages.TokenStyle import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle diff --git a/plugins/kotlin-as-java/src/main/kotlin/transformToJava.kt b/plugins/kotlin-as-java/src/main/kotlin/transformToJava.kt index 69df21eec9e..809f8a3c5c3 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/transformToJava.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/transformToJava.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.kotlinAsJava -import org.jetbrains.dokka.kotlinAsJava.converters.asJava +import org.jetbrains.dokka.kotlinAsJava.converters.KotlinToJavaConverter import org.jetbrains.dokka.kotlinAsJava.transformers.JvmNameDocumentableTransformer import org.jetbrains.dokka.model.DClasslike import org.jetbrains.dokka.model.DFunction @@ -13,17 +13,26 @@ private val JVM_NAME_DOCUMENTABLE_TRANSFORMER by lazy { } fun DPackage.transformToJava(context: DokkaContext): DPackage { - return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this.asJava(), context) + with(KotlinToJavaConverter(context)) { + return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this@transformToJava.asJava(), context) + } } fun DClasslike.transformToJava(context: DokkaContext): DClasslike { - return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this.asJava(), context) + with(KotlinToJavaConverter(context)) { + return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this@transformToJava.asJava(), context) + } } fun DFunction.transformToJava(context: DokkaContext, containingClassName: String, isTopLevel: Boolean = false): List { - return this.asJava(containingClassName, isTopLevel).map { JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(it, context) } + with(KotlinToJavaConverter(context)) { + return this@transformToJava.asJava(containingClassName, isTopLevel) + .map { JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(it, context) } + } } fun DProperty.transformToJava(context: DokkaContext, isTopLevel: Boolean = false, relocateToClass: String? = null): DProperty { - return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this.asJava(isTopLevel, relocateToClass), context) + with(KotlinToJavaConverter(context)) { + return JVM_NAME_DOCUMENTABLE_TRANSFORMER.transform(this@transformToJava.asJava(isTopLevel, relocateToClass), context) + } } diff --git a/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt index 8b07670f090..20bc420c765 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt @@ -1,11 +1,15 @@ package org.jetbrains.dokka.kotlinAsJava.transformers -import org.jetbrains.dokka.kotlinAsJava.converters.asJava +import org.jetbrains.dokka.kotlinAsJava.converters.KotlinToJavaConverter import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer class KotlinAsJavaDocumentableTransformer : DocumentableTransformer { override fun invoke(original: DModule, context: DokkaContext): DModule = - original.copy(packages = original.packages.map { it.asJava() }) + original.copy(packages = original.packages.map { + with(KotlinToJavaConverter(context)) { + it.asJava() + } + }) } diff --git a/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaDocumentableToPageTranslator.kt b/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaDocumentableToPageTranslator.kt index 80c3a3dea5c..92a9f18283f 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaDocumentableToPageTranslator.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaDocumentableToPageTranslator.kt @@ -4,19 +4,17 @@ import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.DokkaBaseConfiguration import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.ModulePageNode -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.configuration -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.query -import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.plugability.* import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.analysis.kotlin.KotlinAnalysisPlugin class KotlinAsJavaDocumentableToPageTranslator(context: DokkaContext) : DocumentableToPageTranslator { private val configuration = configuration(context) private val commentsToContentConverter = context.plugin().querySingle { commentsToContentConverter } private val signatureProvider = context.plugin().querySingle { signatureProvider } private val customTagContentProviders = context.plugin().query { customTagContentProvider } + private val documentableAnalyzer = context.plugin().querySingle { documentableAnalyzer } private val logger: DokkaLogger = context.logger override fun invoke(module: DModule): ModulePageNode = @@ -25,6 +23,7 @@ class KotlinAsJavaDocumentableToPageTranslator(context: DokkaContext) : Document commentsToContentConverter, signatureProvider, logger, - customTagContentProviders + customTagContentProviders, + documentableAnalyzer ).pageForModule(module) -} \ No newline at end of file +} diff --git a/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaPageCreator.kt b/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaPageCreator.kt index ad3c8b0e4bb..5af5607c4fc 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaPageCreator.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/translators/KotlinAsJavaPageCreator.kt @@ -3,24 +3,27 @@ package org.jetbrains.dokka.kotlinAsJava.translators import org.jetbrains.dokka.base.DokkaBaseConfiguration import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter -import org.jetbrains.dokka.base.translators.documentables.DefaultPageCreator import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider +import org.jetbrains.dokka.base.translators.documentables.DefaultPageCreator import org.jetbrains.dokka.model.DProperty import org.jetbrains.dokka.pages.MemberPageNode import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.analysis.kotlin.DocumentableAnalyzer class KotlinAsJavaPageCreator( configuration: DokkaBaseConfiguration?, commentsToContentConverter: CommentsToContentConverter, signatureProvider: SignatureProvider, logger: DokkaLogger, - customTagContentProviders: List + customTagContentProviders: List, + documentableAnalyzer: DocumentableAnalyzer ) : DefaultPageCreator( configuration, commentsToContentConverter, signatureProvider, logger, - customTagContentProviders = customTagContentProviders + customTagContentProviders = customTagContentProviders, + documentableAnalyzer = documentableAnalyzer ) { override fun pageForProperty(p: DProperty): MemberPageNode? = null -} \ No newline at end of file +} diff --git a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt index 031f5ee8b25..ab11120ab4f 100644 --- a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt +++ b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt @@ -12,8 +12,13 @@ import org.jetbrains.dokka.pages.* import org.junit.Assert import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test -import signatures.* -import utils.* +import signatures.Parameter +import signatures.Parameters +import signatures.firstSignature +import signatures.renderedContent +import utils.A +import utils.TestOutputWriterPlugin +import utils.match import kotlin.test.assertEquals import kotlin.test.assertNotNull diff --git a/plugins/mathjax/build.gradle.kts b/plugins/mathjax/build.gradle.kts index 8b155862f3c..4c5724504fb 100644 --- a/plugins/mathjax/build.gradle.kts +++ b/plugins/mathjax/build.gradle.kts @@ -7,15 +7,15 @@ plugins { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) + implementation(projects.plugins.base) + implementation(kotlin("reflect")) + testImplementation(libs.jsoup) testImplementation(projects.plugins.base.baseTestUtils) testImplementation(projects.core.contentMatcherTestUtils) testImplementation(kotlin("test-junit")) - testImplementation(projects.kotlinAnalysis) - testImplementation(projects.core.testApi) testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) diff --git a/plugins/mathjax/src/test/kotlin/MathjaxPluginTest.kt b/plugins/mathjax/src/test/kotlin/MathjaxPluginTest.kt index 0f713708be2..c603e588bf8 100644 --- a/plugins/mathjax/src/test/kotlin/MathjaxPluginTest.kt +++ b/plugins/mathjax/src/test/kotlin/MathjaxPluginTest.kt @@ -1,8 +1,8 @@ package mathjaxTest +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.mathjax.LIB_PATH import org.jetbrains.dokka.mathjax.MathjaxPlugin -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jsoup.Jsoup import org.junit.jupiter.api.Test import utils.TestOutputWriterPlugin diff --git a/plugins/templating/build.gradle.kts b/plugins/templating/build.gradle.kts index 1111bfad2f9..333daf2256a 100644 --- a/plugins/templating/build.gradle.kts +++ b/plugins/templating/build.gradle.kts @@ -12,23 +12,16 @@ registerDokkaArtifactPublication("templating-plugin") { dependencies { compileOnly(projects.core) + api(libs.jsoup) - implementation(kotlin("reflect")) implementation(projects.plugins.base) + implementation(kotlin("reflect")) implementation(libs.kotlinx.coroutines.core) - implementation(libs.jackson.kotlin) - constraints { - implementation(libs.jackson.databind) { - because("CVE-2022-42003") - } - } - implementation(libs.kotlinx.html) - implementation(libs.jsoup) testImplementation(projects.plugins.base.baseTestUtils) - testImplementation(projects.core.testApi) testImplementation(platform(libs.junit.bom)) testImplementation(libs.junit.jupiter) + testImplementation(libs.kotlinx.html) } diff --git a/plugins/versioning/build.gradle.kts b/plugins/versioning/build.gradle.kts index 370338a8298..68db9d1c347 100644 --- a/plugins/versioning/build.gradle.kts +++ b/plugins/versioning/build.gradle.kts @@ -11,22 +11,20 @@ registerDokkaArtifactPublication("versioning-plugin") { dependencies { compileOnly(projects.core) - implementation(kotlin("reflect")) + implementation(projects.plugins.base) implementation(projects.plugins.templating) - implementation(projects.plugins.templating) + implementation(kotlin("reflect")) implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.html) + implementation(libs.apacheMaven.artifact) implementation(libs.jackson.kotlin) constraints { implementation(libs.jackson.databind) { because("CVE-2022-42003") } } - implementation(libs.kotlinx.html) - - implementation(libs.jsoup) - implementation(libs.apacheMaven.artifact) testImplementation(projects.core.testApi) testImplementation(platform(libs.junit.bom)) diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt index 6ab81d3107a..43abdb9cab2 100644 --- a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt @@ -4,11 +4,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import org.jetbrains.dokka.renderers.PostAction import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.query import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.renderers.PostAction import org.jetbrains.dokka.templates.TemplateProcessingStrategy import org.jetbrains.dokka.templates.TemplatingPlugin import java.io.File @@ -51,4 +51,4 @@ class DefaultPreviousDocumentationCopyPostAction(private val context: DokkaConte versionRootContent.copyTo(targetParent.resolve(versionRootContent.name), overwrite = true) } } -} \ No newline at end of file +} diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt index 184e61bb374..a7f4fac075a 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt @@ -10,7 +10,7 @@ internal class DokkaArtifacts(private val project: Project) { private fun fromModuleName(name: String): Dependency = project.dependencies.create("org.jetbrains.dokka:$name:${DokkaVersion.version}") - val dokkaAnalysis get() = fromModuleName("dokka-analysis") + val kotlinAnalysisDescriptors get() = fromModuleName("kotlin-analysis-descriptors") val allModulesPage get() = fromModuleName("all-modules-page-plugin") val dokkaCore get() = fromModuleName("dokka-core") val dokkaBase get() = fromModuleName("dokka-base") diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt index e27fee3068f..46712c81eda 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -393,7 +393,7 @@ open class GradleDokkaSourceSetBuilder( * * @see [GradleSourceLinkBuilder] for details. */ - @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 + @Suppress("DEPRECATION") fun sourceLink(c: Closure) { val configured = org.gradle.util.ConfigureUtil.configure(c, GradleSourceLinkBuilder(project)) sourceLinks.add(configured) @@ -415,7 +415,7 @@ open class GradleDokkaSourceSetBuilder( * * @see [GradlePackageOptionsBuilder] for details. */ - @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 + @Suppress("DEPRECATION") fun perPackageOption(c: Closure) { val configured = org.gradle.util.ConfigureUtil.configure(c, GradlePackageOptionsBuilder(project)) perPackageOptions.add(configured) @@ -437,7 +437,7 @@ open class GradleDokkaSourceSetBuilder( * * @see [GradleExternalDocumentationLinkBuilder] for details. */ - @Suppress("DEPRECATION") // TODO [beresnev] ConfigureUtil will be removed in Gradle 8 + @Suppress("DEPRECATION") fun externalDocumentationLink(c: Closure) { val link = org.gradle.util.ConfigureUtil.configure(c, GradleExternalDocumentationLinkBuilder(project)) externalDocumentationLinks.add(link) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/gradleConfigurations.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/gradleConfigurations.kt index 86dd37160f6..6c1a6cf086c 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/gradleConfigurations.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/gradleConfigurations.kt @@ -25,7 +25,7 @@ internal fun Project.maybeCreateDokkaPluginConfiguration(dokkaTaskName: String, extendsFrom(maybeCreateDokkaDefaultPluginConfiguration()) attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME)) isCanBeConsumed = false - dependencies.add(project.dokkaArtifacts.dokkaAnalysis) // compileOnly in base plugin + dependencies.add(project.dokkaArtifacts.kotlinAnalysisDescriptors) dependencies.add(project.dokkaArtifacts.dokkaBase) dependencies.addAll(additionalDependencies) } diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt index c1e0c85b66a..9594887c241 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import kotlin.test.Test import kotlin.test.assertEquals +import org.jetbrains.dokka.gradle.utils.withDependencies_ class ConfigureWithKotlinSourceSetGistTest { @Test @@ -96,7 +97,7 @@ class ConfigureWithKotlinSourceSetGistTest { /* Make sure to remove dependencies that cannot be resolved during test */ project.configurations.configureEach { - withDependencies { + withDependencies_ { removeIf { dependency -> dependency !is FileCollectionDependency } } } diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinSourceSetGistTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinSourceSetGistTest.kt index c40b5811e0c..713109bf5a1 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinSourceSetGistTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinSourceSetGistTest.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.gradle +import org.jetbrains.dokka.gradle.utils.withDependencies_ import org.gradle.api.artifacts.FileCollectionDependency import org.gradle.kotlin.dsl.get import org.gradle.testfixtures.ProjectBuilder @@ -117,7 +118,7 @@ class KotlinSourceSetGistTest { /* Only work with file dependencies */ project.configurations.forEach { configuration -> - configuration.withDependencies { + configuration.withDependencies_ { removeIf { dependency -> dependency !is FileCollectionDependency } diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index 64293332388..23317a0cda9 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -426,7 +426,7 @@ abstract class AbstractDokkaMojo(private val defaultDokkaPlugins: List