diff options
Diffstat (limited to 'subprojects')
225 files changed, 0 insertions, 17311 deletions
diff --git a/subprojects/analysis-java-psi/README.md b/subprojects/analysis-java-psi/README.md deleted file mode 100644 index d2bbd080..00000000 --- a/subprojects/analysis-java-psi/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Analysis: Java PSI - -An internal module for parsing Java sources. Defines no stable public API and is not published anywhere. - -Used by the Kotlin analysis artifacts to provide support for mixed-language (Kotlin+Java) projects. diff --git a/subprojects/analysis-java-psi/api/analysis-java-psi.api b/subprojects/analysis-java-psi/api/analysis-java-psi.api deleted file mode 100644 index 6b4d444f..00000000 --- a/subprojects/analysis-java-psi/api/analysis-java-psi.api +++ /dev/null @@ -1,152 +0,0 @@ -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 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 <init> (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 <init> ()V - public final fun getDocCommentCreators ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getDocCommentFinder ()Lorg/jetbrains/dokka/analysis/java/doccomment/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 <init> (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 <init> (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 <init> (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 <init> (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 <init> (Ljava/lang/String;)V -} - -public final class org/jetbrains/dokka/analysis/java/ThrowsJavadocTag$Companion { -} - -public abstract interface class org/jetbrains/dokka/analysis/java/doccomment/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/doccomment/DocCommentCreator { - public abstract fun create (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/doccomment/DocComment; -} - -public final class org/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory { - public fun <init> (Ljava/util/List;)V - public final fun fromElement (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/doccomment/DocComment; -} - -public final class org/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder { - public fun <init> (Lorg/jetbrains/dokka/utilities/DokkaLogger;Lorg/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory;)V - public final fun findClosestToElement (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/analysis/java/doccomment/DocComment; -} - -public abstract interface class org/jetbrains/dokka/analysis/java/doccomment/DocumentationContent { - public abstract fun getTag ()Lorg/jetbrains/dokka/analysis/java/JavadocTag; - public abstract fun resolveSiblings ()Ljava/util/List; -} - -public abstract interface class org/jetbrains/dokka/analysis/java/parsers/DocCommentParser { - public abstract fun canParse (Lorg/jetbrains/dokka/analysis/java/doccomment/DocComment;)Z - public abstract fun parse (Lorg/jetbrains/dokka/analysis/java/doccomment/DocComment;Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode; -} - -public final class org/jetbrains/dokka/analysis/java/parsers/JavadocParser : org/jetbrains/dokka/analysis/java/parsers/JavaDocumentationParser { - public fun <init> (Ljava/util/List;Lorg/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder;)V - public fun parseDocumentation (Lcom/intellij/psi/PsiNamedElement;)Lorg/jetbrains/dokka/model/doc/DocumentationNode; -} - -public final class org/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext { - public fun <init> ()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/parsers/doctag/InheritDocTagContentProvider { - public abstract fun canConvert (Lorg/jetbrains/dokka/analysis/java/doccomment/DocumentationContent;)Z - public abstract fun convertToHtml (Lorg/jetbrains/dokka/analysis/java/doccomment/DocumentationContent;Lorg/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext;)Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/java/util/PsiDocumentableSource : org/jetbrains/dokka/model/DocumentableSource { - public fun <init> (Lcom/intellij/psi/PsiNamedElement;)V - public fun computeLineNumber ()Ljava/lang/Integer; - public fun getPath ()Ljava/lang/String; - public final fun getPsi ()Lcom/intellij/psi/PsiNamedElement; -} - -public final class org/jetbrains/dokka/analysis/java/util/PsiUtilKt { - public static final fun from (Lorg/jetbrains/dokka/links/DRI$Companion;Lcom/intellij/psi/PsiElement;)Lorg/jetbrains/dokka/links/DRI; -} - diff --git a/subprojects/analysis-java-psi/build.gradle.kts b/subprojects/analysis-java-psi/build.gradle.kts deleted file mode 100644 index d46d64f0..00000000 --- a/subprojects/analysis-java-psi/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -plugins { - id("org.jetbrains.conventions.kotlin-jvm") -} - -dependencies { - compileOnly(projects.core) - - api(libs.intellij.java.psi.api) - - implementation(projects.subprojects.analysisMarkdownJb) - - implementation(libs.intellij.java.psi.impl) - implementation(libs.intellij.platform.util.api) - implementation(libs.intellij.platform.util.rt) - - implementation(libs.kotlinx.coroutines.core) - implementation(libs.jsoup) -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt deleted file mode 100644 index 3b8ff25b..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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.DokkaPsiParser -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<JavaAnalysisPlugin>().querySingle { projectProvider } - val project = projectProvider.getProject(sourceSet, context) - - val sourceRootsExtractor = context.plugin<JavaAnalysisPlugin>().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<PsiJavaFile>) -> - docParser.parsePackage(packageName, psiFiles) - }, - documentation = emptyMap(), - expectPresentInSet = null, - sourceSets = setOf(sourceSet) - ) - } - } - - private fun createPsiParser(sourceSet: DokkaSourceSet, context: DokkaContext): DokkaPsiParser { - val projectProvider = context.plugin<JavaAnalysisPlugin>().querySingle { projectProvider } - val docCommentParsers = context.plugin<JavaAnalysisPlugin>().query { docCommentParsers } - return DokkaPsiParser( - sourceSetData = sourceSet, - project = projectProvider.getProject(sourceSet, context), - logger = context.logger, - javadocParser = JavadocParser( - docCommentParsers = docCommentParsers, - docCommentFinder = context.plugin<JavaAnalysisPlugin>().docCommentFinder - ), - javaPsiDocCommentParser = docCommentParsers.single { it is JavaPsiDocCommentParser } as JavaPsiDocCommentParser, - lightMethodChecker = context.plugin<JavaAnalysisPlugin>().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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt deleted file mode 100644 index 9426adf1..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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.doccomment.DocCommentCreator -import org.jetbrains.dokka.analysis.java.doccomment.DocCommentFactory -import org.jetbrains.dokka.analysis.java.doccomment.DocCommentFinder -import org.jetbrains.dokka.analysis.java.doccomment.JavaDocCommentCreator -import org.jetbrains.dokka.analysis.java.parsers.DocCommentParser -import org.jetbrains.dokka.analysis.java.parsers.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.analysis.java.util.NoopIntellijLoggerFactory -import org.jetbrains.dokka.plugability.* -import java.io.File - - -@InternalDokkaApi -public interface ProjectProvider { - public fun getProject(sourceSet: DokkaSourceSet, context: DokkaContext): Project -} - -@InternalDokkaApi -public interface SourceRootsExtractor { - public fun extract(sourceSet: DokkaSourceSet, context: DokkaContext): List<File> -} - -@InternalDokkaApi -public interface BreakingAbstractionKotlinLightMethodChecker { - // TODO [beresnev] not even sure it's needed, but left for compatibility and to preserve behaviour - public fun isLightAnnotation(annotation: PsiAnnotation): Boolean - public fun isLightAnnotationAttribute(attribute: JvmAnnotationAttribute): Boolean -} - -@InternalDokkaApi -public class JavaAnalysisPlugin : DokkaPlugin() { - - // single - public val projectProvider: ExtensionPoint<ProjectProvider> by extensionPoint() - - // single - public val sourceRootsExtractor: ExtensionPoint<SourceRootsExtractor> by extensionPoint() - - // multiple - public val docCommentCreators: ExtensionPoint<DocCommentCreator> by extensionPoint() - - // multiple - public val docCommentParsers: ExtensionPoint<DocCommentParser> by extensionPoint() - - // none or more - public val inheritDocTagContentProviders: ExtensionPoint<InheritDocTagContentProvider> by extensionPoint() - - // TODO [beresnev] figure out a better way depending on what it's used for - public val kotlinLightMethodChecker: ExtensionPoint<BreakingAbstractionKotlinLightMethodChecker> by extensionPoint() - - private val docCommentFactory by lazy { - DocCommentFactory(query { docCommentCreators }.reversed()) - } - - public val docCommentFinder: 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt deleted file mode 100644 index 23aee764..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java - -import com.intellij.psi.PsiMethod -import org.jetbrains.dokka.InternalDokkaApi - -@InternalDokkaApi -public sealed class JavadocTag( - public val name: String -) - -public object AuthorJavadocTag : JavadocTag("author") -public object DeprecatedJavadocTag : JavadocTag("deprecated") -public object DescriptionJavadocTag : JavadocTag("description") -public object ReturnJavadocTag : JavadocTag("return") -public object SinceJavadocTag : JavadocTag("since") - -public class ParamJavadocTag( - public val method: PsiMethod, - public val paramName: String, - public val paramIndex: Int -) : JavadocTag(name) { - public companion object { - public const val name: String = "param" - } -} - -public class SeeJavadocTag( - public val qualifiedReference: String -) : JavadocTag(name) { - public companion object { - public const val name: String = "see" - } -} - -public sealed class ThrowingExceptionJavadocTag( - name: String, - public val exceptionQualifiedName: String? -) : JavadocTag(name) - -public class ThrowsJavadocTag(exceptionQualifiedName: String?) : ThrowingExceptionJavadocTag(name, exceptionQualifiedName) { - public companion object { - public const val name: String = "throws" - } -} - -public class ExceptionJavadocTag(exceptionQualifiedName: String?) : ThrowingExceptionJavadocTag(name, exceptionQualifiedName) { - public companion object { - public const val name: String = "exception" - } -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt deleted file mode 100644 index 5b19a42d..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java - -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.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: JavaPsiDocCommentParser, - private val project: Project -) { - fun isDocumented(psiElement: PsiElement): Boolean = psiElement is PsiMethod - && (psiElement.isSyntheticEnumValuesMethod() || psiElement.isSyntheticEnumValueOfMethod()) - - fun getDocumentation(psiElement: PsiElement): DocumentationNode? { - val psiMethod = psiElement as? PsiMethod ?: return null - val templatePath = when { - psiMethod.isSyntheticEnumValuesMethod() -> ENUM_VALUES_TEMPLATE_PATH - psiMethod.isSyntheticEnumValueOfMethod() -> ENUM_VALUEOF_TEMPLATE_PATH - else -> return null - } - val docComment = loadSyntheticDoc(templatePath) ?: return null - return javadocParser.parsePsiDocComment(docComment, psiElement) - } - - private fun loadSyntheticDoc(path: String): PsiDocComment? { - val text = javaClass.getResource(path)?.readText() ?: return null - return JavaPsiFacade.getElementFactory(project).createDocCommentFromText(text) - } -} - -private fun PsiMethod.isSyntheticEnumValuesMethod() = this.isSyntheticEnumFunction() && this.name == "values" -private fun PsiMethod.isSyntheticEnumValueOfMethod() = this.isSyntheticEnumFunction() && this.name == "valueOf" -private fun PsiMethod.isSyntheticEnumFunction() = this is SyntheticElement && this.containingClass?.isEnum == true - diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocComment.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocComment.kt deleted file mode 100644 index be5f7eaa..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocComment.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.JavadocTag - -/** - * MUST override equals and hashcode - */ -@InternalDokkaApi -public interface DocComment { - public fun hasTag(tag: JavadocTag): Boolean - - public fun resolveTag(tag: JavadocTag): List<DocumentationContent> -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentCreator.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentCreator.kt deleted file mode 100644 index 2e22c77c..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentCreator.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.InternalDokkaApi - -@InternalDokkaApi -public interface DocCommentCreator { - public fun create(element: PsiNamedElement): DocComment? -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory.kt deleted file mode 100644 index 4647d4d9..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.InternalDokkaApi - -@InternalDokkaApi -public class DocCommentFactory( - private val docCommentCreators: List<DocCommentCreator> -) { - public fun fromElement(element: PsiNamedElement): DocComment? { - docCommentCreators.forEach { creator -> - val comment = creator.create(element) - if (comment != null) { - return comment - } - } - return null - } -} - diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder.kt deleted file mode 100644 index 18463e0e..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -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 -public class DocCommentFinder( - private val logger: DokkaLogger, - private val docCommentFactory: DocCommentFactory, -) { - public 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<PsiDocComment>() - .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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocumentationContent.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocumentationContent.kt deleted file mode 100644 index 64e9ceb8..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocumentationContent.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.JavadocTag - -@InternalDokkaApi -public interface DocumentationContent { - public val tag: JavadocTag - - public fun resolveSiblings(): List<DocumentationContent> -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocComment.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocComment.kt deleted file mode 100644 index 066b5162..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocComment.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import com.intellij.psi.PsiElement -import com.intellij.psi.javadoc.PsiDocComment -import com.intellij.psi.javadoc.PsiDocTag -import org.jetbrains.dokka.analysis.java.* -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 -import org.jetbrains.dokka.utilities.firstIsInstanceOrNull - -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).firstIsInstanceOrNull<PsiDocTag>() - ?.resolveToElement() - ?.getKotlinFqName() == tag.exceptionQualifiedName - - override fun resolveTag(tag: JavadocTag): List<DocumentationContent> { - 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<DocumentationContent> { - val resolvedParamElements = comment.resolveTag(tag) - .filterIsInstance<PsiDocTag>() - .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<DocumentationContent> { - 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<PsiElement> { - return when (tag) { - DescriptionJavadocTag -> this.descriptionElements.toList() - else -> this.findTagsByName(tag.name).toList() - } - } - - private fun List<PsiElement>.withoutReferenceLink(): List<PsiElement> = 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocCommentCreator.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocCommentCreator.kt deleted file mode 100644 index 79da0ee2..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocCommentCreator.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/PsiDocumentationContent.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/PsiDocumentationContent.kt deleted file mode 100644 index aa1fe120..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/PsiDocumentationContent.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.doccomment - -import com.intellij.psi.PsiElement -import com.intellij.psi.javadoc.PsiDocTag -import org.jetbrains.dokka.analysis.java.JavadocTag -import org.jetbrains.dokka.analysis.java.util.contentElementsWithSiblingIfNeeded - -internal data class PsiDocumentationContent( - val psiElement: PsiElement, - override val tag: JavadocTag -) : DocumentationContent { - - override fun resolveSiblings(): List<DocumentationContent> { - return if (psiElement is PsiDocTag) { - psiElement.contentElementsWithSiblingIfNeeded() - .map { content -> PsiDocumentationContent(content, tag) } - } else { - listOf(this) - } - } - -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt deleted file mode 100644 index 1cd7d604..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DocCommentParser.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DocCommentParser.kt deleted file mode 100644 index 4a381e80..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DocCommentParser.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.model.doc.DocumentationNode - -@InternalDokkaApi -public interface DocCommentParser { - public fun canParse(docComment: DocComment): Boolean - public fun parse(docComment: DocComment, context: PsiNamedElement): DocumentationNode -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt deleted file mode 100644 index b8dabe42..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers - -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.BreakingAbstractionKotlinLightMethodChecker -import org.jetbrains.dokka.analysis.java.SyntheticElementDocumentationProvider -import org.jetbrains.dokka.analysis.java.getVisibility -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<String, Bound>() - - 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> T.toSourceSetDependent() = mapOf(sourceSetData to this) - - suspend fun parsePackage(packageName: String, psiFiles: List<PsiJavaFile>): 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<Int>() - val superMethods = mutableListOf<Pair<PsiMethod, DRI>>() - val superFieldsKeys = hashSetOf<Int>() - val superFields = mutableListOf<Pair<PsiField, DRI>>() - 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<PsiClassType>.getSuperTypesPsiClasses(): List<Pair<PsiClass, JavaClassKindTypes>> { - 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<PsiEnumConstant>().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<DFunction> { - 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<Param> { - 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<DocumentableSource> { - 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<ExtraModifiers>.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<PsiAnnotation>.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 <T : AnnotationTarget> PsiTypeParameter.annotations(): PropertyContainer<T> = this.annotations.toList().toListOfAnnotations().annotations() - private fun <T : AnnotationTarget> PsiType.annotations(): PropertyContainer<T> = this.annotations.toList().toListOfAnnotations().annotations() - - private fun <T : AnnotationTarget> List<Annotations.Annotation>.annotations(): PropertyContainer<T> = - 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<Annotations.Annotation>) -> 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.isExtends -> Covariance(getBound(type.extendsBound)) - type.isSuper -> Contravariance(getBound(type.superBound)) - // If the type isn't explicitly bounded, it still has an implicit `extends Object` bound - type.extendsBound != PsiType.NULL -> Covariance(getBound(type.extendsBound)) - 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<DTypeParameter> { - fun mapBounds(bounds: Array<JvmReferenceType>): List<Bound> = - 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<Pair<PsiMethod, DRI>>, - 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<PsiMethod>, 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<PsiAnnotation>.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<String>::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<PsiAnnotation>? { - 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<PsiJavaCodeReferenceElement>()?.resolve() -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt deleted file mode 100644 index 1e4c9f2d..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.doccomment.JavaDocComment -import org.jetbrains.dokka.analysis.java.parsers.doctag.PsiDocTagParser -import org.jetbrains.dokka.analysis.java.util.* -import org.jetbrains.dokka.analysis.markdown.jb.MARKDOWN_ELEMENT_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<DocTag>): CustomDocTag { - val isFile = (tags.singleOrNull() as? CustomDocTag)?.name == MARKDOWN_ELEMENT_FILE_NAME - return if (isFile) { - tags.first() as CustomDocTag - } else { - CustomDocTag(tags, name = MARKDOWN_ELEMENT_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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt deleted file mode 100644 index 140e64c9..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.doccomment.DocCommentFinder -import org.jetbrains.dokka.model.doc.DocumentationNode - -internal fun interface JavaDocumentationParser { - fun parseDocumentation(element: PsiNamedElement): DocumentationNode -} - -@InternalDokkaApi -public class JavadocParser( - private val docCommentParsers: List<DocCommentParser>, - 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext.kt deleted file mode 100644 index e8df804b..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers.doctag - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.DocumentationNode -import java.util.* - -@InternalDokkaApi -public 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<String, DRI>() - - /** - * 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<String, DocumentationNode>() - - /** - * @return key of the stored DRI - */ - public fun store(dri: DRI): String { - val id = dri.toString() - driMap[id] = dri - return id - } - - /** - * @return key of the stored documentation node - */ - public fun store(documentationNode: DocumentationNode): String { - val id = UUID.randomUUID().toString() - inheritDocSections[id] = documentationNode - return id - } - - public fun getDri(id: String): DRI? = driMap[id] - - public fun getDocumentationNode(id: String): DocumentationNode? = inheritDocSections[id] -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt deleted file mode 100644 index 195ce79a..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers.doctag - -import org.jetbrains.dokka.analysis.markdown.jb.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<DocTag> { - return Jsoup.parseBodyFragment(html) - .body() - .childNodes() - .flatMap { convertHtmlNode(it) } - } - - private fun convertHtmlNode(node: Node, keepFormatting: Boolean = false): List<DocTag> = 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<DocTag> { - val tagName = element.tagName() - val children = element.childNodes() - .flatMap { convertHtmlNode(it, keepFormatting = keepFormatting || tagName == "pre" || tagName == "code") } - - fun ifChildrenPresent(operation: () -> DocTag): List<DocTag> { - 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>): 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<Text>().joinToString { it.body }) - } - } -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagContentProvider.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagContentProvider.kt deleted file mode 100644 index a09f85c4..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagContentProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers.doctag - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent - -@InternalDokkaApi -public interface InheritDocTagContentProvider { - public fun canConvert(content: DocumentationContent): Boolean - public fun convertToHtml(content: DocumentationContent, docTagParserContext: DocTagParserContext): String -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt deleted file mode 100644 index 344f69b1..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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.doccomment.* -import org.jetbrains.dokka.analysis.java.doccomment.JavaDocComment -import org.jetbrains.dokka.analysis.java.parsers.CommentResolutionContext - -internal class InheritDocTagResolver( - private val docCommentFactory: DocCommentFactory, - private val docCommentFinder: DocCommentFinder, - private val contentProviders: List<InheritDocTagContentProvider> -) { - internal fun convertToHtml(content: DocumentationContent, docTagParserContext: DocTagParserContext): String? { - return contentProviders - .firstOrNull { it.canConvert(content) } - ?.convertToHtml(content, docTagParserContext) - } - - internal fun resolveContent(context: CommentResolutionContext): List<DocumentationContent>? { - 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<DocumentationContent> { - 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<DocumentationContent> { - 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<DocumentationContent> { - 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<PsiMethod> = - baseMethod.findSuperMethods().filter { docCommentFinder.findClosestToElement(it)?.hasTag(javadocTag) == true } -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt deleted file mode 100644 index 18c506f6..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.parsers.doctag - -import com.intellij.psi.PsiElement -import com.intellij.psi.javadoc.PsiDocTag -import org.jetbrains.dokka.analysis.java.parsers.CommentResolutionContext -import org.jetbrains.dokka.model.doc.* - -/** - * Parses [PsiElement] of [PsiDocTag] into Dokka's [DocTag] - */ -internal class PsiDocTagParser( - private val inheritDocTagResolver: InheritDocTagResolver -) { - fun parse( - psiElements: Iterable<PsiElement>, - commentResolutionContext: CommentResolutionContext - ): List<DocTag> = parse(asParagraph = false, psiElements, commentResolutionContext) - - fun parseAsParagraph( - psiElements: Iterable<PsiElement>, - commentResolutionContext: CommentResolutionContext - ): List<DocTag> = parse(asParagraph = true, psiElements, commentResolutionContext) - - private fun parse( - asParagraph: Boolean, - psiElements: Iterable<PsiElement>, - commentResolutionContext: CommentResolutionContext - ): List<DocTag> { - val docTagParserContext = DocTagParserContext() - - val psiToHtmlConverter = PsiElementToHtmlConverter(inheritDocTagResolver) - val elementsHtml = psiToHtmlConverter.convert(psiElements, docTagParserContext, commentResolutionContext) - ?: return emptyList() - - val htmlToDocTagConverter = HtmlToDocTagConverter(docTagParserContext) - val html = if (asParagraph) "<p>$elementsHtml</p>" else elementsHtml - return htmlToDocTagConverter.convertToDocTag(html) - } -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt deleted file mode 100644 index 07aaacb9..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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.doccomment.DocumentationContent -import org.jetbrains.dokka.analysis.java.JavadocTag -import org.jetbrains.dokka.analysis.java.doccomment.PsiDocumentationContent -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 = "<pre(\\s+.*)?>".toRegex() - private val preClosingTagRegex = "</pre>".toRegex() - - fun convert( - psiElements: Iterable<PsiElement>, - 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<PsiElement>): 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<PsiDocToken>().joinToString(" ") { - it.stringifyElementAsText(keepFormatting = false).orEmpty() - }) - - "code" -> "<code data-inline>${dataElementsAsText(this)}</code>" - "literal" -> "<literal>${dataElementsAsText(this)}</literal>" - "index" -> "<index>${this.children.filterIsInstance<PsiDocTagValue>().joinToString { it.text }}</index>" - "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 """<a data-dri="${driId.htmlEscape()}">${label.ifBlank { defaultLabel().text }}</a>""" - } - } -} - -private fun PsiElement.stringifyElementAsText(keepFormatting: Boolean, previousElement: PsiElement? = null) = - if (keepFormatting) { - /* - For values in the <pre> 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 <pre> 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: <a href="...">Something</a> since then the space will be displayed in the following text - * - next line starts with a <p> or <pre> 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("</") - - return (nextSibling as? PsiWhiteSpace)?.text?.startsWith("\n ") == true && - (getNextSiblingIgnoringWhitespace() as? PsiDocToken)?.tokenType != JavaDocTokenTypes.INSTANCE.commentEnd() && - nextNotEmptySibling?.isLeadingAsterisk() == true && - furtherNotEmptySibling?.tokenType == JavaDocTokenTypes.INSTANCE.commentData() && - !endsWithAnUnclosedTag -} - - diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/CoreCopyPaste.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/CoreCopyPaste.kt deleted file mode 100644 index e875fb82..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/CoreCopyPaste.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.util - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.AncestryNode -import org.jetbrains.dokka.model.TypeConstructor - -// TODO [beresnev] copy-pasted -internal fun AncestryNode.typeConstructorsBeingExceptions(): List<TypeConstructor> { - fun traverseSupertypes(ancestry: AncestryNode): List<TypeConstructor> = - 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/NoopIntellijLogger.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/NoopIntellijLogger.kt deleted file mode 100644 index e5cb6ef0..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/NoopIntellijLogger.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.util - -import com.intellij.openapi.diagnostic.Attachment -import com.intellij.openapi.diagnostic.DefaultLogger -import com.intellij.openapi.diagnostic.Logger - -internal class NoopIntellijLoggerFactory : Logger.Factory { - override fun getLoggerInstance(p0: String): Logger = NoopIntellijLogger -} - -/** - * Ignores all messages passed to it - */ -internal object NoopIntellijLogger : DefaultLogger(null) { - override fun isDebugEnabled(): Boolean = false - override fun isTraceEnabled(): Boolean = false - - override fun debug(message: String?) {} - override fun debug(t: Throwable?) {} - override fun debug(message: String?, t: Throwable?) {} - override fun debug(message: String, vararg details: Any?) {} - override fun debugValues(header: String, values: MutableCollection<*>) {} - - override fun trace(message: String?) {} - override fun trace(t: Throwable?) {} - - override fun info(message: String?) {} - override fun info(message: String?, t: Throwable?) {} - override fun info(t: Throwable) {} - - override fun warn(message: String?, t: Throwable?) {} - override fun warn(message: String?) {} - override fun warn(t: Throwable) {} - - override fun error(message: String?, t: Throwable?, vararg details: String?) {} - override fun error(message: String?) {} - override fun error(message: Any?) {} - override fun error(message: String?, vararg attachments: Attachment?) {} - override fun error(message: String?, t: Throwable?, vararg attachments: Attachment?) {} - override fun error(message: String?, vararg details: String?) {} - override fun error(message: String?, t: Throwable?) {} - override fun error(t: Throwable) {} -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt deleted file mode 100644 index de24552e..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.util - -// TODO [beresnev] copy-paste - -internal fun propertyNamesBySetMethodName(methodName: String): List<String> = - 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt deleted file mode 100644 index 190fc5bd..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.util - -import com.intellij.psi.PsiField -import com.intellij.psi.PsiMethod -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 - - -internal data class PsiFunctionsHolder( - val regularFunctions: List<PsiMethod>, - val accessors: Map<PsiField, List<PsiMethod>> -) - -internal fun splitFunctionsAndAccessors(fields: Array<PsiField>, methods: Array<PsiMethod>): PsiFunctionsHolder { - val fieldsByName = fields.associateBy { it.name } - val regularFunctions = mutableListOf<PsiMethod>() - val accessors = mutableMapOf<PsiField, MutableList<PsiMethod>>() - methods.forEach { method -> - val possiblePropertyNamesForFunction = method.getPossiblePropertyNamesForFunction() - val field = possiblePropertyNamesForFunction.firstNotNullOfOrNull { fieldsByName[it] } - if (field != null && method.isAccessorFor(field)) { - accessors.getOrPut(field, ::mutableListOf).add(method) - } else { - regularFunctions.add(method) - } - } - - val accessorLookalikes = removeNonAccessorsReturning(accessors) - regularFunctions.addAll(accessorLookalikes) - - return PsiFunctionsHolder(regularFunctions, accessors) -} - -private fun PsiMethod.getPossiblePropertyNamesForFunction(): List<String> { - 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 - */ -private fun removeNonAccessorsReturning( - fieldAccessors: MutableMap<PsiField, MutableList<PsiMethod>> -): List<PsiMethod> { - val nonAccessors = mutableListOf<PsiMethod>() - fieldAccessors.entries.removeIf { (field, methods) -> - if (methods.size == 1 && methods[0].isSetterFor(field)) { - nonAccessors.add(methods[0]) - true - } else { - false - } - } - return nonAccessors -} - -internal fun PsiMethod.isAccessorFor(field: PsiField): Boolean { - return (this.isGetterFor(field) || this.isSetterFor(field)) - && !field.getVisibility().isPublicAPI() - && this.getVisibility().isPublicAPI() -} - -internal fun PsiMethod.isGetterFor(field: PsiField): Boolean { - return this.returnType == field.type && !this.hasParameters() -} - -internal fun PsiMethod.isSetterFor(field: PsiField): Boolean { - return parameterList.getParameter(0)?.type == field.type && parameterList.getParametersCount() == 1 -} - -private fun Visibility.isPublicAPI() = when(this) { - KotlinVisibility.Public, - KotlinVisibility.Protected, - JavaVisibility.Public, - JavaVisibility.Protected -> true - else -> false -} diff --git a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt deleted file mode 100644 index 573f479e..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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 - -internal fun PsiDocComment.hasTag(tag: JavadocTag): Boolean = - when (tag) { - DescriptionJavadocTag -> descriptionElements.isNotEmpty() - else -> findTagByName(tag.name) != null - } - -internal fun PsiDocTag.contentElementsWithSiblingIfNeeded(): List<PsiElement> = 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt deleted file mode 100644 index 162f940e..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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 -import org.jetbrains.dokka.utilities.firstIsInstanceOrNull - -// TODO [beresnev] copy-paste - -internal val PsiElement.parentsWithSelf: Sequence<PsiElement> - get() = generateSequence(this) { if (it is PsiFile) null else it.parent } - -@InternalDokkaApi -public fun DRI.Companion.from(psi: PsiElement): DRI = psi.parentsWithSelf.run { - val psiMethod = firstIsInstanceOrNull<PsiMethod>() - val psiField = firstIsInstanceOrNull<PsiField>() - val classes = filterIsInstance<PsiClass>().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 -> firstIsInstanceOrNull<PsiParameter>()?.let { - val callable = firstIsInstanceOrNull<PsiMethod>() - 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<PsiElement> { - return object : Sequence<PsiElement> { - override fun iterator(): Iterator<PsiElement> { - var next: PsiElement? = this@siblings - return object : Iterator<PsiElement> { - 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 -public class PsiDocumentableSource( - public val psi: PsiNamedElement -) : DocumentableSource { - override val path: String = psi.containingFile.virtualFile.path - - override fun computeLineNumber(): Int? { - val range = psi.getChildOfType<PsiIdentifier>()?.textRange ?: psi.textRange - val doc = PsiDocumentManager.getInstance(psi.project).getDocument(psi.containingFile) - // IJ uses 0-based line-numbers; external source browsers use 1-based - return doc?.getLineNumber(range.startOffset)?.plus(1) - } -} - -public inline fun <reified T : PsiElement> 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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt deleted file mode 100644 index 00658ce9..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.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 <T, R : Any> Iterable<T>.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/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/resolveToGetDri.kt b/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/resolveToGetDri.kt deleted file mode 100644 index aabe57c0..00000000 --- a/subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/resolveToGetDri.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.java.util - -import com.intellij.psi.PsiElement - -// TODO [beresnev] get rid of -internal fun PsiElement.resolveToGetDri(): PsiElement? = - reference?.resolve() diff --git a/subprojects/analysis-java-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/subprojects/analysis-java-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin deleted file mode 100644 index 9fa991c2..00000000 --- a/subprojects/analysis-java-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. -# - -org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin diff --git a/subprojects/analysis-kotlin-api/README.md b/subprojects/analysis-kotlin-api/README.md deleted file mode 100644 index 5b03b297..00000000 --- a/subprojects/analysis-kotlin-api/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Analysis: Kotlin API - -Public API for interacting with Kotlin analysis, regardless of implementation. Contains no business logic. - -Can be used to request additional information about Kotlin declarations. - -Has to be used as a `compileOnly` dependency as Dokka bundles it by default in all runners. - -The actual implementation (K1/K2/etc) will be resolved and bootstrapped during runtime, so the -user must not think about it. diff --git a/subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api b/subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api deleted file mode 100644 index c65dfe5a..00000000 --- a/subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api +++ /dev/null @@ -1,85 +0,0 @@ -public final class org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { - public fun <init> ()V -} - -public final class org/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage : java/lang/Enum { - public static final field JAVA Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage; - public static final field KOTLIN Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage; - public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage; - public static fun values ()[Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/DocumentableSourceLanguageParser { - public abstract fun getLanguage (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider { - public abstract fun findClasslike (Lorg/jetbrains/dokka/links/DRI;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Lorg/jetbrains/dokka/model/DClasslike; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/FullClassHierarchyBuilder { - public abstract fun build (Lorg/jetbrains/dokka/model/DModule;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/InheritanceBuilder { - public abstract fun build (Ljava/util/Map;)Ljava/util/List; -} - -public final class org/jetbrains/dokka/analysis/kotlin/internal/InheritanceNode { - public fun <init> (Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;Z)V - public synthetic fun <init> (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/analysis/kotlin/internal/InheritanceNode; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/analysis/kotlin/internal/InheritanceNode;Lorg/jetbrains/dokka/links/DRI;Ljava/util/List;Ljava/util/List;ZILjava/lang/Object;)Lorg/jetbrains/dokka/analysis/kotlin/internal/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/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { - public fun <init> ()V - public final fun getDocumentableSourceLanguageParser ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getExternalDocumentablesProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getFullClassHierarchyBuilder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getInheritanceBuilder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getKotlinToJavaService ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getModuleAndPackageDocumentationReader ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getSampleProviderFactory ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getSyntheticDocumentableDetector ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/KotlinToJavaService { - public abstract fun findAsJava (Lorg/jetbrains/dokka/links/DRI;)Lorg/jetbrains/dokka/links/DRI; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/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/dokka/analysis/kotlin/internal/SampleProvider : java/lang/AutoCloseable { - public abstract fun getSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet; -} - -public final class org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet { - public fun <init> (Ljava/lang/String;Ljava/lang/String;)V - public final fun getBody ()Ljava/lang/String; - public final fun getImports ()Ljava/lang/String; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SampleProviderFactory { - public abstract fun build ()Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider; -} - -public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector { - public abstract fun isSynthetic (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Z -} - diff --git a/subprojects/analysis-kotlin-api/build.gradle.kts b/subprojects/analysis-kotlin-api/build.gradle.kts deleted file mode 100644 index bf3b5b3c..00000000 --- a/subprojects/analysis-kotlin-api/build.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -import org.jetbrains.registerDokkaArtifactPublication - -plugins { - id("org.jetbrains.conventions.kotlin-jvm") - id("org.jetbrains.conventions.maven-publish") - `java-test-fixtures` -} - -dependencies { - compileOnly(projects.core) - - testFixturesApi(projects.core) - - testImplementation(kotlin("test")) - testImplementation(projects.subprojects.analysisKotlinDescriptors) -} - -disableTestFixturesPublishing() - -/** - * Test fixtures are automatically published by default, which at this moment in time is unwanted - * as the test api is unstable and is internal to the Dokka project, so it shouldn't be used outside of it. - * - * @see https://docs.gradle.org/current/userguide/java_testing.html#ex-disable-publishing-of-test-fixtures-variants - */ -fun disableTestFixturesPublishing() { - val javaComponent = components["java"] as AdhocComponentWithVariants - javaComponent.withVariantsFromConfiguration(configurations["testFixturesApiElements"]) { skip() } - javaComponent.withVariantsFromConfiguration(configurations["testFixturesRuntimeElements"]) { skip() } -} - -registerDokkaArtifactPublication("analysisKotlinApi") { - artifactId = "analysis-kotlin-api" -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt deleted file mode 100644 index 7d434bd5..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin - -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement - -public class KotlinAnalysisPlugin : DokkaPlugin() { - - /* - * This is where stable public API will go. - * - * No stable public API for now. - */ - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/DocumentableSourceLanguageParser.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/DocumentableSourceLanguageParser.kt deleted file mode 100644 index 116adb06..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/DocumentableSourceLanguageParser.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.model.WithSources - -@InternalDokkaApi -public enum class DocumentableLanguage { - JAVA, KOTLIN -} - -@InternalDokkaApi -public interface DocumentableSourceLanguageParser { - public fun getLanguage(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): DocumentableLanguage? -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt deleted file mode 100644 index 7c564880..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ExternalDocumentablesProvider.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.DClasslike - -/** - * Service that can be queried with [DRI] and source set to obtain a documentable for classlike. - * - * There are some cases when there is a need to process documentables of classlikes that were not defined - * in the project itself but are somehow related to the symbols defined in the documented project (e.g. are supertypes - * of classes defined in project). - */ -@InternalDokkaApi -public fun interface ExternalDocumentablesProvider { - - /** - * Returns [DClasslike] matching provided [DRI] in specified source set. - * - * Result is null if compiler haven't generated matching class descriptor. - */ - public fun findClasslike(dri: DRI, sourceSet: DokkaConfiguration.DokkaSourceSet): DClasslike? -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/FullClassHierarchyBuilder.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/FullClassHierarchyBuilder.kt deleted file mode 100644 index 5b975fd8..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/FullClassHierarchyBuilder.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.SourceSetDependent - -@InternalDokkaApi -public typealias Supertypes = List<DRI> - -@InternalDokkaApi -public typealias ClassHierarchy = SourceSetDependent<Map<DRI, Supertypes>> - -@InternalDokkaApi -public interface FullClassHierarchyBuilder { - public suspend fun build(module: DModule): ClassHierarchy -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InheritanceBuilder.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InheritanceBuilder.kt deleted file mode 100644 index 32077cde..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InheritanceBuilder.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.Documentable - -@InternalDokkaApi -public interface InheritanceBuilder { - public fun build(documentables: Map<DRI, Documentable>): List<InheritanceNode> -} - -@InternalDokkaApi -public data class InheritanceNode( - val dri: DRI, - val children: List<InheritanceNode> = emptyList(), - val interfaces: List<DRI> = emptyList(), - val isInterface: Boolean = false -) { - override fun equals(other: Any?): Boolean = other is InheritanceNode && other.dri == dri - override fun hashCode(): Int = dri.hashCode() -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt deleted file mode 100644 index 0ef1399a..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAnalysisPlugin.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import org.jetbrains.dokka.plugability.ExtensionPoint -import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement - -/** - * A plugin for internal use, has no stable public API and thus must not be used by third party, - * external plugins. If you need any of the given API stabilized, please create an issue describing your use case. - */ -@InternalDokkaApi -public class InternalKotlinAnalysisPlugin : DokkaPlugin() { - - public val fullClassHierarchyBuilder: ExtensionPoint<FullClassHierarchyBuilder> by extensionPoint() - - public val syntheticDocumentableDetector: ExtensionPoint<SyntheticDocumentableDetector> by extensionPoint() - - public val moduleAndPackageDocumentationReader: ExtensionPoint<ModuleAndPackageDocumentationReader> by extensionPoint() - - public val kotlinToJavaService: ExtensionPoint<KotlinToJavaService> by extensionPoint() - - public val inheritanceBuilder: ExtensionPoint<InheritanceBuilder> by extensionPoint() - - public val externalDocumentablesProvider: ExtensionPoint<ExternalDocumentablesProvider> by extensionPoint() - - public val documentableSourceLanguageParser: ExtensionPoint<DocumentableSourceLanguageParser> by extensionPoint() - - public val sampleProviderFactory: ExtensionPoint<SampleProviderFactory> by extensionPoint() - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/KotlinToJavaService.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/KotlinToJavaService.kt deleted file mode 100644 index 1ce47031..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/KotlinToJavaService.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.links.DRI - -@InternalDokkaApi -public interface KotlinToJavaService { - /** - * E.g. - * kotlin.Throwable -> java.lang.Throwable - * kotlin.Int -> java.lang.Integer - * kotlin.Int.Companion -> kotlin.jvm.internal.IntCompanionObject - * kotlin.Nothing -> java.lang.Void - * kotlin.IntArray -> null - * kotlin.Function3 -> kotlin.jvm.functions.Function3 - * kotlin.coroutines.SuspendFunction3 -> kotlin.jvm.functions.Function4 - * kotlin.Function42 -> kotlin.jvm.functions.FunctionN - * kotlin.coroutines.SuspendFunction42 -> kotlin.jvm.functions.FunctionN - * kotlin.reflect.KFunction3 -> kotlin.reflect.KFunction - * kotlin.reflect.KSuspendFunction3 -> kotlin.reflect.KFunction - * kotlin.reflect.KFunction42 -> kotlin.reflect.KFunction - * kotlin.reflect.KSuspendFunction42 -> kotlin.reflect.KFunction - */ - public fun findAsJava(kotlinDri: DRI): DRI? -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ModuleAndPackageDocumentationReader.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ModuleAndPackageDocumentationReader.kt deleted file mode 100644 index 70419e0e..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/ModuleAndPackageDocumentationReader.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.DPackage -import org.jetbrains.dokka.model.SourceSetDependent -import org.jetbrains.dokka.model.doc.DocumentationNode - -@InternalDokkaApi -public interface ModuleAndPackageDocumentationReader { - public fun read(module: DModule): SourceSetDependent<DocumentationNode> - public fun read(pkg: DPackage): SourceSetDependent<DocumentationNode> - public fun read(module: DokkaConfiguration.DokkaModuleDescription): DocumentationNode? -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt deleted file mode 100644 index 472d17f0..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi - -@InternalDokkaApi -public interface SampleProviderFactory { - /** - * [SampleProvider] is a short-lived closeable instance. - * It assumes that [SampleProvider] scope of use is not big. - * Otherwise, it can lead to high memory consumption / leaks during Dokka running. - */ - public fun build(): SampleProvider -} - -/** - * It is closeable. - * Otherwise, there is a chance of high memory consumption / leak. - * In general case, it creates a separate project to analysis samples directories. - */ -@InternalDokkaApi -public interface SampleProvider: AutoCloseable { - public class SampleSnippet( - public val imports: String, - public val body: String - ) - - /** - * @return [SampleSnippet] or null if it has not found by [fqLink] - */ - public fun getSample(sourceSet: DokkaConfiguration.DokkaSourceSet, fqLink: String): SampleSnippet? -} diff --git a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector.kt b/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector.kt deleted file mode 100644 index 0a2d64de..00000000 --- a/subprojects/analysis-kotlin-api/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.internal - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.model.Documentable - -// TODO [beresnev] isSynthetic could be a property of Documentable -@InternalDokkaApi -public interface SyntheticDocumentableDetector { - public fun isSynthetic(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean -} diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt deleted file mode 100644 index f6632f60..00000000 --- a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/java/SampleJavaAnalysisTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.jvm.java - -import org.jetbrains.dokka.analysis.test.api.javaTestProject -import org.jetbrains.dokka.analysis.test.api.parse -import kotlin.test.Test -import kotlin.test.assertEquals - -class SampleJavaAnalysisTest { - - /** - * Used as a sample for [javaTestProject] - */ - @Test - fun sample() { - val testProject = javaTestProject { - dokkaConfiguration { - moduleName = "java-module-name-for-unit-test" - - javaSourceSet { - // source-set specific configuration - } - } - javaFile(pathFromSrc = "org/jetbrains/dokka/test/java/Bar.java") { - +""" - public class Bar { - public static void bar() { - System.out.println("Bar"); - } - } - """ - } - } - - val module = testProject.parse() - assertEquals("java-module-name-for-unit-test", module.name) - assertEquals(1, module.packages.size) - - val pckg = module.packages[0] - assertEquals("org.jetbrains.dokka.test.java", pckg.name) - assertEquals(1, pckg.classlikes.size) - - val fooClass = pckg.classlikes[0] - assertEquals("Bar", fooClass.name) - } -} diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt deleted file mode 100644 index 6c73af1f..00000000 --- a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/kotlin/SampleKotlinJvmAnalysisTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.jvm.kotlin - -import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.parse -import kotlin.test.Test -import kotlin.test.assertEquals - -class SampleKotlinJvmAnalysisTest { - - /** - * Used as a sample for [kotlinJvmTestProject] - */ - @Test - fun sample() { - val testProject = kotlinJvmTestProject { - dokkaConfiguration { - moduleName = "kotlin-jvm-module-name-for-unit-test" - - kotlinSourceSet { - // source-set specific configuration - } - } - ktFile(pathFromSrc = "org/jetbrains/dokka/test/kotlin/MyFile.kt") { - +"public class Foo {}" - } - } - - val module = testProject.parse() - assertEquals("kotlin-jvm-module-name-for-unit-test", module.name) - assertEquals(1, module.packages.size) - - val pckg = module.packages[0] - assertEquals("org.jetbrains.dokka.test.kotlin", pckg.name) - assertEquals(1, pckg.classlikes.size) - - val fooClass = pckg.classlikes[0] - assertEquals("Foo", fooClass.name) - } -} diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt deleted file mode 100644 index fec2ceb8..00000000 --- a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/jvm/mixed/SampleMixedJvmAnalysisTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.jvm.mixed - -import org.jetbrains.dokka.analysis.test.api.mixedJvmTestProject -import org.jetbrains.dokka.analysis.test.api.parse -import kotlin.test.Test -import kotlin.test.assertEquals - -class SampleMixedJvmAnalysisTest { - - /** - * Used as a sample for [mixedJvmTestProject] - */ - @Test - fun sample() { - val testProject = mixedJvmTestProject { - dokkaConfiguration { - moduleName = "mixed-project-module-name-for-unit-test" - - jvmSourceSet { - // source-set specific configuration - } - } - - kotlinSourceDirectory { - ktFile(pathFromSrc = "test/MyFile.kt") { - +"fun foo(): String = \"Foo\"" - } - javaFile(pathFromSrc = "test/MyJavaFileInKotlin.java") { - +""" - public class MyJavaFileInKotlin { - public static void bar() { - System.out.println("Bar"); - } - } - """ - } - } - - javaSourceDirectory { - ktFile(pathFromSrc = "test/MyFile.kt") { - +"fun bar(): String = \"Bar\"" - } - javaFile(pathFromSrc = "test/MyJavaFileInJava.java") { - +""" - public class MyJavaFileInJava { - public static void bar() { - System.out.println("Bar"); - } - } - """ - } - } - } - - val module = testProject.parse() - assertEquals("mixed-project-module-name-for-unit-test", module.name) - assertEquals(1, module.packages.size) - - val pckg = module.packages[0] - assertEquals("test", pckg.name) - - assertEquals(2, pckg.classlikes.size) - assertEquals(2, pckg.functions.size) - - val firstClasslike = pckg.classlikes[0] - assertEquals("MyJavaFileInKotlin", firstClasslike.name) - - val secondClasslike = pckg.classlikes[1] - assertEquals("MyJavaFileInJava", secondClasslike.name) - - val firstFunction = pckg.functions[0] - assertEquals("bar", firstFunction.name) - - val secondFunction = pckg.functions[1] - assertEquals("foo", secondFunction.name) - } -} diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt deleted file mode 100644 index 55507023..00000000 --- a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/moduledocs/PackageDocumentationAnalysisTest.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.moduledocs - -import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.useServices -import org.jetbrains.dokka.model.doc.CodeInline -import org.jetbrains.dokka.model.doc.Description -import org.jetbrains.dokka.model.doc.P -import org.jetbrains.dokka.model.doc.Text -import kotlin.test.Test -import kotlin.test.assertEquals - -class PackageDocumentationAnalysisTest { - - @Test - fun `should parse include description for a nested package in kotlin-jvm`() { - val testProject = kotlinJvmTestProject { - dokkaConfiguration { - kotlinSourceSet { - includes = setOf("/documentation/cool-package-description.md") - } - } - - ktFile(pathFromSrc = "org/jetbrains/dokka/pckg/docs/test/TestFile.kt") { - +"class TestFile {}" - } - - mdFile(pathFromProjectRoot = "/documentation/cool-package-description.md") { - +""" - # Package org.jetbrains.dokka.pckg.docs.test - - This is my test description for the package `org.jetbrains.dokka.pckg.docs.test`, - which contains only one file named TestFile.kt. It has one empty class. - """ - } - } - - testProject.useServices { context -> - val pckg = context.module.packages.single { it.name == "org.jetbrains.dokka.pckg.docs.test" } - - val allPackageDocs = moduleAndPackageDocumentationReader.read(pckg) - assertEquals(1, allPackageDocs.size) - - val sourceSetPackageDocs = allPackageDocs.entries.single().value - assertEquals(1, sourceSetPackageDocs.children.size) - - val descriptionTag = sourceSetPackageDocs.children.single() as Description - assertEquals(1, descriptionTag.children.size) - - val paragraphTag = descriptionTag.children.single() as P - assertEquals(3, paragraphTag.children.size) - - val expectedParagraphChildren = listOf( - Text("This is my test description for the package "), - CodeInline(children = listOf(Text( - "org.jetbrains.dokka.pckg.docs.test" - ))), - Text(", which contains only one file named TestFile.kt. It has one empty class.") - ) - assertEquals(expectedParagraphChildren, paragraphTag.children) - } - } -} diff --git a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt b/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt deleted file mode 100644 index 618e28a8..00000000 --- a/subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/sample/SampleAnalysisTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.sample - -import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.useServices -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -class SampleAnalysisTest { - - @Test - fun `should return sources of a kotlin sample`() { - val testProject = kotlinJvmTestProject { - dokkaConfiguration { - kotlinSourceSet { - additionalSourceRoots = setOf("/samples") - } - } - sampleFile("/samples/stringListOf-sample.kt", fqPackageName = "org.jetbrains.dokka.sample.generator") { - +""" - import org.jetbrains.dokka.DokkaConfiguration - import org.jetbrains.dokka.DokkaGenerator - import org.jetbrains.dokka.utilities.DokkaLogger - - fun runGenerator(configuration: DokkaConfiguration, logger: DokkaLogger) { - DokkaGenerator(configuration, logger).generate() - } - """ - } - } - - testProject.useServices { context -> - val sampleSourceSet = context.configuration.sourceSets.single() - - val sampleProvider = sampleProviderFactory.build() - val sample = sampleProvider.getSample(sampleSourceSet, "org.jetbrains.dokka.sample.generator.runGenerator") - assertNotNull(sample) - - val expectedImports = listOf( - "import org.jetbrains.dokka.DokkaConfiguration", - "import org.jetbrains.dokka.DokkaGenerator", - "import org.jetbrains.dokka.utilities.DokkaLogger" - ).joinToString(separator = "\n") - - val expectedBody = "DokkaGenerator(configuration, logger).generate()" - - assertEquals(expectedImports, sample.imports) - assertEquals(expectedBody, sample.body) - } - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt deleted file mode 100644 index 64bfd7a3..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestData.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api - -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * Represents some sort of data of a [TestProject], which normally consists of a number of [TestDataFile]. - * - * This can be anything that can usually be found in a user-defined project: - * programming language source code, markdown files with documentation, samples, etc. - * - * This virtual test data will be materialized and created physically before running Dokka, - * and then passed as input files into it. - */ -@AnalysisTestDslMarker -interface TestData { - fun getFiles(): List<TestDataFile> -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt deleted file mode 100644 index 5b2233ba..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestDataFile.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api - -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * Represents a single file of a project's [TestData]. - * - * This file will be materialized and created physically before running Dokka, - * and then passed as one of the input files into it. - * - * @property pathFromProjectRoot this file's path from the root of the project. Must begin - * with `/` to not confuse it with relative paths. - */ -@AnalysisTestDslMarker -abstract class TestDataFile(val pathFromProjectRoot: String) { - - init { - require(pathFromProjectRoot.startsWith("/")) { - "File path going from the project's root must begin with \"/\" to not confuse it with relative paths." - } - } - - /** - * Returns the string contents of this file. - * - * The contents must be complete, as if the user themselves wrote it. For Kotlin files, - * it should return Kotlin source code (including the package and all import statements). - * For `.md` files, it should return valid Markdown documentation. - * - * These contents will be used to populate the real input file to be used by Dokka. - */ - abstract fun getContents(): String -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt deleted file mode 100644 index 9c0fa936..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProject.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.analysis.TestAnalysisContext -import org.jetbrains.dokka.analysis.test.api.analysis.TestAnalysisServices -import org.jetbrains.dokka.analysis.test.api.analysis.TestProjectAnalyzer -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaConfigurationBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.util.withTempDirectory -import org.jetbrains.dokka.model.DModule - -/** - * Represents a virtual test project (as if it's user-defined) that will be used to run Dokka. - * - * A test project consists of some Dokka configuration (represented as [TestDokkaConfiguration]) - * and some project-specific data like source code and markdown files (represented as [TestData]). - * - * See [kotlinJvmTestProject], [javaTestProject] and [mixedJvmTestProject] for convenient ways - * of bootstrapping test projects. - * - * See [parse] and [useServices] functions to learn how to run Dokka with this project as input. - */ -interface TestProject { - - /** - * Verifies that this project is valid from the user's and Dokka's perspectives. - * Exists to save time with debugging difficult to catch mistakes, such as copy-pasted - * test data that is not applicable to this project. - * - * Must throw an exception if there's misconfiguration, incorrect / corrupted test data - * or API misuse. - * - * Verification is performed before running Dokka on this project. - */ - fun verify() - - /** - * Returns the configuration of this project, which will then be mapped to [DokkaConfiguration]. - * - * This is typically constructed using [BaseTestDokkaConfigurationBuilder]. - */ - fun getConfiguration(): TestDokkaConfiguration - - /** - * Returns this project's test data - a collection of source code files, markdown files - * and whatever else that can be usually found in a user-defined project. - */ - fun getTestData(): TestData -} - -/** - * Runs Dokka on the given [TestProject] and returns the generated documentable model. - * - * Can be used to verify the resulting documentable model, to check that - * everything was parsed and converted correctly. - * - * Usage example: - * ```kotlin - * val testProject = kotlinJvmTestProject { - * ... - * } - * - * val module: DModule = testProject.parse() - * ``` - */ -fun TestProject.parse(): DModule = TestProjectAnalyzer.parse(this) - -/** - * Runs Dokka on the given [TestProject] and provides not only the resulting documentable model, - * but analysis context and configuration as well, which gives you the ability to call public - * analysis services. - * - * Usage example: - * - * ```kotlin - * val testProject = kotlinJvmTestProject { - * ... - * } - * - * testProject.useServices { context -> - * val pckg: DPackage = context.module.packages.single() - * - * // use `moduleAndPackageDocumentationReader` service to get documentation of a package - * val allPackageDocs: SourceSetDependent<DocumentationNode> = moduleAndPackageDocumentationReader.read(pckg) - * } - * ``` - */ -fun TestProject.useServices(block: TestAnalysisServices.(context: TestAnalysisContext) -> Unit) { - withTempDirectory { tempDirectory -> - val (services, context) = TestProjectAnalyzer.analyze(this, tempDirectory) - services.block(context) - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt deleted file mode 100644 index 81a20243..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/TestProjectFactory.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api - -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestProject -import org.jetbrains.dokka.analysis.test.api.jvm.kotlin.KotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.jvm.mixed.MixedJvmTestProject -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * Creates a single-target Kotlin/JVM test project that only has Kotlin source code. - * - * See [javaTestProject] and [mixedJvmTestProject] if you want to check interoperability - * with other JVM languages. - * - * By default, the sources are put in `/src/main/kotlin`, and the JVM version of Kotlin's - * standard library is available on classpath. - * - * See [parse] and [useServices] functions to learn how to run Dokka with this project as input. - * - * @sample org.jetbrains.dokka.analysis.test.jvm.kotlin.SampleKotlinJvmAnalysisTest.sample - */ -fun kotlinJvmTestProject(init: (@AnalysisTestDslMarker KotlinJvmTestProject).() -> Unit): TestProject { - val testData = KotlinJvmTestProject() - testData.init() - return testData -} - -/** - * Creates a Java-only test project. - * - * This can be used to test Dokka's Java support or specific - * corner cases related to parsing Java sources. - * - * By default, the sources are put in `/src/main/java`. No Kotlin source code is allowed. - * - * See [parse] and [useServices] functions to learn how to run Dokka with this project as input. - * - * @sample org.jetbrains.dokka.analysis.test.jvm.java.SampleJavaAnalysisTest.sample - */ -fun javaTestProject(init: (@AnalysisTestDslMarker JavaTestProject).() -> Unit): TestProject { - val testData = JavaTestProject() - testData.init() - return testData -} - -/** - * Creates a project where a number of JVM language sources are allowed, - * like Java and Kotlin sources co-existing in the same source directory. - * - * This can be used to test interoperability between JVM languages. - * - * By default, this project consists of a single "jvm" source set, which has two source root directories: - * * `/src/main/kotlin` - * * `/src/main/java` - * - * See [parse] and [useServices] functions to learn how to run Dokka with this project as input. - * - * @sample org.jetbrains.dokka.analysis.test.jvm.mixed.SampleMixedJvmAnalysisTest.sample - */ -fun mixedJvmTestProject(init: (@AnalysisTestDslMarker MixedJvmTestProject).() -> Unit): TestProject { - val testProject = MixedJvmTestProject() - testProject.init() - return testProject -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt deleted file mode 100644 index de6efb1b..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisContext.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.analysis - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.plugability.DokkaContext - -/** - * Context and data gathered during the analysis of a [TestProject]. - */ -class TestAnalysisContext( - - /** - * The actual [DokkaContext] that was used to run Dokka. - * - * Includes all plugins and classes available on classpath during the analysis. - */ - val context: DokkaContext, - - /** - * The actual [DokkaConfiguration] that was used to run Dokka. - * - * It was initially mapped from [TestDokkaConfiguration], and then added to by Dokka itself. - */ - val configuration: DokkaConfiguration, - - /** - * The entry point to the documentable model of the analyzed [TestProject]. - */ - val module: DModule -) diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt deleted file mode 100644 index ab70bbd4..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestAnalysisServices.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.analysis - -import org.jetbrains.dokka.analysis.kotlin.KotlinAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.internal.ModuleAndPackageDocumentationReader -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProviderFactory - -/** - * Services exposed in [KotlinAnalysisPlugin] that are ready to be used. - * - * This class exists purely for convenience and to reduce boilerplate in tests. - * It is analogous to calling `context.plugin<KotlinAnalysisPlugin>().querySingle { serviceName }`. - */ -class TestAnalysisServices( - val sampleProviderFactory: SampleProviderFactory, - val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader -) diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt deleted file mode 100644 index 1668b53f..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/analysis/TestProjectAnalyzer.kt +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.analysis - -import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.configuration.toDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.parse -import org.jetbrains.dokka.analysis.test.api.useServices -import org.jetbrains.dokka.analysis.test.api.util.withTempDirectory -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.transformers.documentation.DefaultDocumentableMerger -import org.jetbrains.dokka.transformers.documentation.DocumentableMerger -import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator -import org.jetbrains.dokka.utilities.DokkaConsoleLogger -import org.jetbrains.dokka.utilities.LoggingLevel -import java.io.File - -/** - * The main logger used for running Dokka and analyzing projects. - * - * Changing the level to [LoggingLevel.DEBUG] can help with debugging faulty tests - * or tricky corner cases. - */ -val analysisLogger = DokkaConsoleLogger(minLevel = LoggingLevel.INFO) - -/** - * Analyzer of the test projects, it is essentially a very simple Dokka runner. - * - * Takes all virtual files of the given [TestProject], creates the real files for - * them in a temporary directory, and then runs Dokka with this temporary directory - * as the input user project. This allows us to simulate Dokka's behavior and results - * on a made-up project as if it were real and run via the CLI runner. - * - * Executes only a limited number of steps and uses a small subset of [CoreExtensions] - * that are necessary to test the analysis logic. - * - * Works only with single-module projects, where the source code of this project - * resides in the root `src` directory. Works with multiple source sets and targets, - * so both simple Kotlin/JVM and more complicated Kotlin Multiplatform project must work. - */ -object TestProjectAnalyzer { - - /** - * A quick way to analyze a [TestProject], for cases when only the documentable - * model is needed to verify the result. - * - * Creates the input test files, runs Dokka and then deletes them right after the documentable - * model has been created, leaving no trailing files or any other garbage behind. - * - * @see [TestProject.parse] for a user-friendly way to call it - */ - fun parse(testProject: TestProject): DModule { - // since we only need documentables, we can delete the input test files right away - return withTempDirectory(analysisLogger) { tempDirectory -> - val (_, context) = testProject.initialize(outputDirectory = tempDirectory) - generateDocumentableModel(context) - } - } - - /** - * Works in the same way as [parse], but it returns the context and configuration used for - * running Dokka, and does not delete the input test files at the end of the execution - it - * must be taken care of on call site. - * - * @param persistentDirectory a directory that will be used to generate the input test files into. - * It must be available during the test run, especially if services are used, - * otherwise parts of Dokka might not work as expected. Can be safely deleted - * at the end of the test after all asserts have been run. - * - * @see [TestProject.useServices] for a user-friendly way to call it - */ - fun analyze( - testProject: TestProject, - persistentDirectory: File - ): Pair<TestAnalysisServices, TestAnalysisContext> { - val (dokkaConfiguration, dokkaContext) = testProject.initialize(outputDirectory = persistentDirectory) - val analysisServices = createTestAnalysisServices(dokkaContext) - val testAnalysisContext = TestAnalysisContext( - context = dokkaContext, - configuration = dokkaConfiguration, - module = generateDocumentableModel(dokkaContext) - ) - return analysisServices to testAnalysisContext - } - - /** - * Prepares this [TestProject] for analysis by creating - * the test files, setting up context and configuration. - */ - private fun TestProject.initialize(outputDirectory: File): Pair<DokkaConfiguration, DokkaContext> { - analysisLogger.progress("Initializing and verifying project $this") - this.verify() - require(outputDirectory.isDirectory) { - "outputDirectory has to exist and be a directory: $outputDirectory" - } - this.initializeTestFiles(relativeToDir = outputDirectory) - - analysisLogger.progress("Creating configuration and context") - val testDokkaConfiguration = this.getConfiguration() - val dokkaConfiguration = testDokkaConfiguration.toDokkaConfiguration(projectDir = outputDirectory).also { - it.verify() - } - return dokkaConfiguration to createContext(dokkaConfiguration) - } - - /** - * Takes the virtual [TestDataFile] of this [TestProject] and creates - * the real files relative to the [relativeToDir] param. - */ - private fun TestProject.initializeTestFiles(relativeToDir: File) { - analysisLogger.progress("Initializing test files relative to the \"$relativeToDir\" directory") - - this.getTestData().getFiles().forEach { - val testDataFile = relativeToDir.resolve(it.pathFromProjectRoot.removePrefix("/")) - try { - testDataFile.parentFile.mkdirs() - } catch (e: Exception) { - // the IOException thrown from `mkdirs()` has no details and thus is more difficult to debug. - throw IllegalStateException("Unable to create dirs \"${testDataFile.parentFile}\"", e) - } - - analysisLogger.debug("Creating \"${testDataFile.absolutePath}\"") - check(testDataFile.createNewFile()) { - "Unable to create a test file: ${testDataFile.absolutePath}" - } - testDataFile.writeText(it.getContents(), Charsets.UTF_8) - } - } - - /** - * Verifies this [DokkaConfiguration] to make sure there are no unexpected - * parameter option values, such as non-existing classpath entries. - * - * If this method fails, it's likely there's a configuration error in the test, - * or an exception must be made in one of the checks. - */ - private fun DokkaConfiguration.verify() { - this.includes.forEach { verifyFileExists(it) } - this.sourceSets.forEach { sourceSet -> - sourceSet.classpath.forEach { verifyFileExists(it) } - sourceSet.includes.forEach { verifyFileExists(it) } - sourceSet.samples.forEach { verifyFileExists(it) } - // we do not verify sourceRoots since the source directory - // is not guaranteed to exist even if it was configured. - } - } - - private fun verifyFileExists(file: File) { - if (!file.exists() && !file.absolutePath.contains("non-existing")) { - throw IllegalArgumentException( - "The provided file does not exist. Bad test data or configuration? " + - "If it is done intentionally, add \"non-existing\" to the path or the name. File: \"$file\"" - ) - } - } - - private fun createContext(dokkaConfiguration: DokkaConfiguration): DokkaContext { - analysisLogger.progress("Creating DokkaContext from test configuration") - return DokkaContext.create( - configuration = dokkaConfiguration, - logger = analysisLogger, - pluginOverrides = listOf() - ) - } - - /** - * Generates the documentable model by using all available [SourceToDocumentableTranslator] extensions, - * and then merging all the results into a single [DModule] by calling [DocumentableMerger]. - */ - private fun generateDocumentableModel(context: DokkaContext): DModule { - analysisLogger.progress("Generating the documentable model") - val sourceSetModules = context - .configuration - .sourceSets - .map { sourceSet -> translateSources(sourceSet, context) } - .flatten() - - if (sourceSetModules.isEmpty()) { - throw IllegalStateException("Got no modules after translating sources. Is the test data set up?") - } - - return DefaultDocumentableMerger(context).invoke(sourceSetModules) - ?: error("Unable to merge documentables for some reason") - } - - /** - * Translates input source files to the documentable model by using - * all registered [SourceToDocumentableTranslator] core extensions. - */ - private fun translateSources(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): List<DModule> { - val translators = context[CoreExtensions.sourceToDocumentableTranslator] - require(translators.isNotEmpty()) { - "Need at least one source to documentable translator to run tests, otherwise no data will be generated." - } - analysisLogger.debug("Translating sources for ${sourceSet.sourceSetID}") - return translators.map { it.invoke(sourceSet, context) } - } - - /** - * A helper function to query analysis services, to avoid - * boilerplate and misconfiguration in the tests. - * - * The idea is to provide the users with ready-to-use services, - * without them having to know how to query or configure them. - */ - private fun createTestAnalysisServices(context: DokkaContext): TestAnalysisServices { - analysisLogger.progress("Creating analysis services") - val internalPlugin = context.plugin<InternalKotlinAnalysisPlugin>() - return TestAnalysisServices( - sampleProviderFactory = internalPlugin.querySingle { sampleProviderFactory }, - moduleAndPackageDocumentationReader = internalPlugin.querySingle { moduleAndPackageDocumentationReader } - ) - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt deleted file mode 100644 index 5c5a0daf..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfiguration.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.configuration - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.test.api.TestProject - -/** - * Configuration options for [TestProject]. - * - * Represents a trimmed-down version of [DokkaConfiguration] that only - * exposes properties that can be used by Dokka's analysis implementations. - */ -data class TestDokkaConfiguration( - - /** - * Name of this [TestProject]. - * - * @see DokkaConfiguration.moduleName - */ - val moduleName: String, - - /** - * References Markdown files that contain documentation for this module and packages. - * - * Contains paths relative to the root of [TestProject], so it must begin with `/`. - * - * Example: `/docs/module.md` - * - * @see DokkaConfiguration.includes - * @see https://kotlinlang.org/docs/dokka-module-and-package-docs.html - */ - val includes: Set<String> = emptySet(), - - /** - * A number of source directories and their configuration options that - * make up this project. - * - * A multiplatform Kotlin project will typically have multiple source sets - * for the supported platforms, whereas a single Kotlin/JVM project will have only one. - * - * @see TestDokkaSourceSet - */ - val sourceSets: Set<TestDokkaSourceSet> - - -) { - override fun toString(): String { - return "TestDokkaConfiguration(moduleName='$moduleName', includes=$includes, sourceSets=$sourceSets)" - } -} - -/** - * Configuration options for a collection of source files for a specific platform. - * - * Represents a trimmed-down version of [DokkaConfiguration.DokkaSourceSet] that only - * exposes properties that can be used by Dokka's analysis implementations. - * - * @see https://kotlinlang.org/docs/multiplatform-discover-project.html#source-sets - */ -data class TestDokkaSourceSet ( - - /** - * @see DokkaConfiguration.DokkaSourceSet.analysisPlatform - */ - val analysisPlatform: Platform, - - /** - * A unique identifier of this source set in the scope of the project. - * - * It must be unique even if two source sets have the same name, - * the same platform or the same configuration. - * - * @see DokkaConfiguration.DokkaSourceSet.sourceSetID - */ - val sourceSetID: DokkaSourceSetID, - - /** - * A set of source set ids that this source set depends on. - * - * @see DokkaConfiguration.DokkaSourceSet.dependentSourceSets - */ - val dependentSourceSets: Set<DokkaSourceSetID>, - - /** - * A set of directories that contain the source files for this source set. - * - * A source set typically has only one source root directory, but there can be additional - * ones if the project has generated sources that reside separately, or if the `@sample` - * tag is used, and the samples reside in a different directory. - * - * Contains paths relative to the root of [TestProject], so it must begin with `/`. - * - * @see DokkaConfiguration.DokkaSourceSet.sourceRoots - */ - val sourceRoots: Set<String>, - - /** - * A set of JARs to be used for analyzing sources. - * - * If this [TestProject] exposes types from external libraries, Dokka needs to know - * about these libraries so that it can generate correct signatures and documentation. - * - * Contains absolute paths, can be any file, even if it has nothing to do with unit - * tests or test project. - * - * @see DokkaConfiguration.DokkaSourceSet.classpath - */ - val classpath: Set<String>, - - /** - * References Markdown files that contain documentation for this module and packages. - * - * Contains paths relative to the root of [TestProject], so it must begin with `/`. - * - * Example: `/docs/module.md` - * - * @see DokkaConfiguration.DokkaSourceSet.includes - * @see https://kotlinlang.org/docs/dokka-module-and-package-docs.html - */ - val includes: Set<String> = emptySet(), - - /** - * A set of Kotlin files with functions that show how to use certain API. - * - * Contains paths relative to the root of [TestProject], so it must begin with `/`. - * - * Example: `/samples/collectionSamples.kt` - * - * @see DokkaConfiguration.DokkaSourceSet.samples - */ - val samples: Set<String> = emptySet(), - - /** - * Compatibility mode for Kotlin language version X.Y. - * - * Example: `1.9` - * - * @see https://kotlinlang.org/docs/compatibility-modes.html - */ - val languageVersion: String? = null, - - /** - * Compatibility mode for Kotlin API version X.Y. - * - * Example: `1.9` - * - * @see https://kotlinlang.org/docs/compatibility-modes.html - */ - val apiVersion: String? = null, - - -) { - override fun toString(): String { - return "TestDokkaSourceSet(" + - "analysisPlatform=$analysisPlatform, " + - "sourceSetID=$sourceSetID, " + - "dependentSourceSets=$dependentSourceSets, " + - "sourceRoots=$sourceRoots, " + - "classpath=$classpath, " + - "includes=$includes, " + - "samples=$samples, " + - "languageVersion=$languageVersion, " + - "apiVersion=$apiVersion" + - ")" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt deleted file mode 100644 index b6563fb7..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationBuilder.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.configuration - -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * A builder for [TestDokkaConfiguration] that contains base options. - * - * Implementations can override the properties to modify the resulting test - * data or prohibit setting certain properties. - */ -@AnalysisTestDslMarker -abstract class BaseTestDokkaConfigurationBuilder { - - /** - * @see TestDokkaConfiguration.moduleName - */ - abstract var moduleName: String - - - /** - * @see TestDokkaConfiguration.includes - */ - open var includes: Set<String> = emptySet() - - /** - * Verifies that this source set configuration is valid. For example, - * it should check that all file paths are set in the expected format. - * - * Must be invoked manually as part of [TestProject.verify]. - */ - open fun verify() { - includes.forEach { - verifyFilePathStartsWithSlash("includes", it) - verifyFileExtension("includes", it, ".md") - } - } - - abstract fun build(): TestDokkaConfiguration - - override fun toString(): String { - return "BaseTestDokkaConfigurationBuilder(moduleName='$moduleName', includes=$includes)" - } -} - -/** - * A builder for [TestDokkaSourceSet] that contains base options. - * - * Implementations can override the properties to modify the resulting test - * data or prohibit setting certain properties. - */ -@AnalysisTestDslMarker -abstract class BaseTestDokkaSourceSetBuilder { - - /** - * Directories **additional** to the default source roots. - * - * @see TestDokkaSourceSet.sourceRoots - */ - open var additionalSourceRoots: Set<String> = emptySet() - - /** - * JARs **additional** to the default classpath. - * - * @see TestDokkaSourceSet.classpath - */ - open var additionalClasspath: Set<String> = emptySet() - - /** - * @see TestDokkaSourceSet.includes - */ - open var includes: Set<String> = emptySet() - - /** - * @see TestDokkaSourceSet.samples - */ - open var samples: Set<String> = emptySet() - - /** - * @see TestDokkaSourceSet.languageVersion - */ - open var languageVersion: String? = null - - /** - * @see TestDokkaSourceSet.apiVersion - */ - open var apiVersion: String? = null - - /** - * Verifies that this source set configuration is valid. For example, - * it should check that all file paths are set in the expected format. - * - * Must be invoked manually during the verification of the - * higher-level [BaseTestDokkaConfigurationBuilder.verify]. - */ - open fun verify() { - additionalSourceRoots.forEach { - verifyFilePathStartsWithSlash("additionalSourceRoots", it) - } - additionalClasspath.forEach { - // this check can be extended to accept .klib, .class or other files - // as the need for it arises, as long as Dokka supports it - verifyFileExtension("additionalClasspath", it, ".jar") - } - includes.forEach { - verifyFilePathStartsWithSlash("includes", it) - verifyFileExtension("includes", it, ".md") - } - samples.forEach { - verifyFilePathStartsWithSlash("samples", it) - verifyFileExtension("samples", it, ".kt") - } - } - - abstract fun build(): TestDokkaSourceSet - - override fun toString(): String { - return "BaseTestDokkaSourceSetBuilder(" + - "additionalSourceRoots=$additionalSourceRoots, " + - "additionalClasspath=$additionalClasspath, " + - "includes=$includes, " + - "samples=$samples, " + - "languageVersion=$languageVersion, " + - "apiVersion=$apiVersion" + - ")" - } -} - -internal fun verifyFilePathStartsWithSlash(propertyName: String, path: String) { - require(path.startsWith("/")) { - "Property $propertyName must contain paths relative to the root of the project. " + - "Please, prefix it with \"/\" for readability and consistency." - } -} - -internal fun verifyFileExtension(propertyName: String, filePath: String, expectedExtension: String) { - require(filePath.endsWith(expectedExtension)) { - "Property $propertyName only accepts files with \"$expectedExtension\" extension. " + - "Got: \"${filePath.substringAfterLast("/")}\"." - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationMapper.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationMapper.kt deleted file mode 100644 index f6356ab2..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/configuration/TestDokkaConfigurationMapper.kt +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.configuration - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.test.api.util.mapToSet -import java.io.File - -/** - * Maps [TestDokkaConfiguration] to the actual [DokkaConfiguration] that will - * be used to run Dokka; The resulting configuration must be valid from Dokka's perspective. - * - * @receiver test configuration to map to the real one; all file paths must be relative to the - * root of the project. - * @param projectDir the actual project directory that will be used to create test files in; - * the path must be absolute and must exist. - */ -fun TestDokkaConfiguration.toDokkaConfiguration(projectDir: File): DokkaConfiguration { - require(projectDir.exists() && projectDir.isDirectory) { - "Expected the \"projectDir\" File param to exist and be a directory" - } - - val moduleName = this.moduleName - val includes = this.includes.mapToSet { it.relativeTo(projectDir) } - val sourceSets = this.sourceSets.map { it.toDokkaSourceSet(projectDir) } - - return object : DokkaConfiguration { - - /* - * NOTE: The getters need to return data that can be compared by value. - * This means you can't recreate lists of interfaces on every invocation - * as their equals will return false, leading to difficult to trace bugs, - * especially when it comes to `SourceSetDependent<T>` - */ - - override val moduleName: String - get() = moduleName - - override val includes: Set<File> - get() = includes - - override val sourceSets: List<DokkaConfiguration.DokkaSourceSet> - get() = sourceSets - - /* - * The plugin API uses the properties below to initialize plugins found on classpath. - * They are not settable directly in analysis tests, but must not throw any exceptions. - */ - override val pluginsClasspath: List<File> - get() = emptyList() - override val pluginsConfiguration: List<DokkaConfiguration.PluginConfiguration> - get() = emptyList() - - /* - * The properties below are not used by the analysis modules, - * and thus they don't need to be supported. - * - * If one of the properties below starts being used during - * analysis (i.e starts throwing an exception), a corresponding - * test property should be added along with the mapping. - */ - override val moduleVersion: String - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val outputDir: File - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val cacheRoot: File - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val offlineMode: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val failOnWarning: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val modules: List<DokkaConfiguration.DokkaModuleDescription> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val delayTemplateSubstitution: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val suppressObviousFunctions: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val suppressInheritedMembers: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val finalizeCoroutines: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - } -} - -private fun TestDokkaSourceSet.toDokkaSourceSet(relativeToDir: File): DokkaConfiguration.DokkaSourceSet { - val analysisPlatform = this.analysisPlatform - val sourceSetID = this.sourceSetID - val dependentSourceSets = this.dependentSourceSets - val sourceRoots = this.sourceRoots.mapToSet { it.relativeTo(relativeToDir) } - val classpath = this.classpath.map { File(it) } - val includes = this.includes.mapToSet { it.relativeTo(relativeToDir) } - val samples = this.samples.mapToSet { it.relativeTo(relativeToDir) } - val languageVersion = this.languageVersion - val apiVersion = this.apiVersion - - return object : DokkaConfiguration.DokkaSourceSet { - - /* - * NOTE: The getters need to return data that can be compared by value. - * This means you can't recreate lists of interfaces on every invocation - * as their equals will return false, leading to difficult to trace bugs, - * especially when it comes to `SourceSetDependent<T>` - */ - - override val analysisPlatform: Platform - get() = analysisPlatform - - override val sourceSetID: DokkaSourceSetID - get() = sourceSetID - - override val dependentSourceSets: Set<DokkaSourceSetID> - get() = dependentSourceSets - - override val sourceRoots: Set<File> - get() = sourceRoots - - override val classpath: List<File> - get() = classpath - - override val includes: Set<File> - get() = includes - - override val samples: Set<File> - get() = samples - - override val languageVersion: String? - get() = languageVersion - - override val apiVersion: String? - get() = apiVersion - - - /* - * The properties below are not used by the analysis modules, - * and thus they don't need to be supported. - * - * If one of the properties below starts being used during - * analysis (i.e starts throwing an exception), a corresponding - * test property should be added along with the mapping. - */ - override val displayName: String - get() = throw NotImplementedError("Not expected to be used by analysis modules") - @Suppress("OVERRIDE_DEPRECATION") - override val includeNonPublic: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val reportUndocumented: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val skipEmptyPackages: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val skipDeprecated: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val jdkVersion: Int - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val sourceLinks: Set<DokkaConfiguration.SourceLinkDefinition> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val perPackageOptions: List<DokkaConfiguration.PackageOptions> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val externalDocumentationLinks: Set<DokkaConfiguration.ExternalDocumentationLink> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val noStdlibLink: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val noJdkLink: Boolean - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val suppressedFiles: Set<File> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - override val documentedVisibilities: Set<DokkaConfiguration.Visibility> - get() = throw NotImplementedError("Not expected to be used by analysis modules") - } -} - -private fun String.relativeTo(dir: File): File { - return dir.resolve(this.removePrefix("/")) -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaConfigurationBuilder.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaConfigurationBuilder.kt deleted file mode 100644 index 6775fa21..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaConfigurationBuilder.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.java - -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaConfigurationBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaSourceSetBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaSourceSet -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * An implementation of [BaseTestDokkaConfigurationBuilder] specific to [JavaTestProject]. - */ -class JavaTestConfigurationBuilder : BaseTestDokkaConfigurationBuilder() { - override var moduleName: String = "javaTestProject" - - private val javaSourceSetBuilder = JavaTestSourceSetBuilder() - - @AnalysisTestDslMarker - fun javaSourceSet(fillSourceSet: JavaTestSourceSetBuilder.() -> Unit) { - fillSourceSet(javaSourceSetBuilder) - } - - override fun verify() { - super.verify() - javaSourceSetBuilder.verify() - } - - override fun build(): TestDokkaConfiguration { - return TestDokkaConfiguration( - moduleName = moduleName, - includes = includes, - sourceSets = setOf(javaSourceSetBuilder.build()) - ) - } -} - -/** - * An implementation of [BaseTestDokkaSourceSetBuilder] specific to [JavaTestProject]. - * - * Defines sensible defaults that should cover the majority of simple projects. - */ -class JavaTestSourceSetBuilder : BaseTestDokkaSourceSetBuilder() { - override fun build(): TestDokkaSourceSet { - return TestDokkaSourceSet( - analysisPlatform = Platform.jvm, - sourceSetID = DokkaSourceSetID(scopeId = "project", sourceSetName = "java"), - dependentSourceSets = setOf(), - sourceRoots = additionalSourceRoots + setOf(JavaTestProject.DEFAULT_SOURCE_ROOT), - classpath = additionalClasspath, // TODO [beresnev] is kotlin jvm stdlib needed here? - includes = includes, - samples = samples, - languageVersion = languageVersion, - apiVersion = apiVersion - ) - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaFileCreator.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaFileCreator.kt deleted file mode 100644 index 2a79210f..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaFileCreator.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.java - -/** - * Declares a capability that a `.java` file can be created in the scope of the implementation. - */ -interface JavaFileCreator { - - /** - * Creates a `.java` file. - * - * By default, the package of this file is deduced automatically from the [pathFromSrc] param. - * For example, for a path `org/jetbrains/dokka/test` the package will be `org.jetbrains.dokka.test`. - * It is normally prohibited for Java files to have a mismatch in package and file path, so it - * cannot be overridden. - * - * @param pathFromSrc path relative to the source code directory of the project. - * Must contain packages (if any) and end in `.java`. - * Example: `org/jetbrains/dokka/test/MyClass.java` - */ - fun javaFile(pathFromSrc: String, fillFile: JavaTestDataFile.() -> Unit) -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestData.kt deleted file mode 100644 index 48705e78..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestData.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.java - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.util.filePathToPackageName - -/** - * A container for populating and holding Java source code test data. - * - * This container exists so that common creation, population and verification logic - * can be reused, instead of having to implement [JavaFileCreator] multiple times. - * - * @param pathToJavaSources path to the `src` directory in which Java sources must reside. - * Must be relative to the root of the test project. Example: `/src/main/java` - * @see TestData - */ -class JavaTestData( - private val pathToJavaSources: String -) : TestData, JavaFileCreator { - - private val files = mutableListOf<TestDataFile>() - - override fun javaFile(pathFromSrc: String, fillFile: JavaTestDataFile.() -> Unit) { - val fileName = pathFromSrc.substringAfterLast("/") - check(fileName.endsWith(".java")) { "Java files are expected to have .java extension" } - - val testDataFile = JavaTestDataFile( - fullyQualifiedPackageName = filePathToPackageName(pathFromSrc), - pathFromProjectRoot = "$pathToJavaSources/$pathFromSrc", - ) - fillFile(testDataFile) - testDataFile.checkFileNameIsPresent(fileName) - files.add(testDataFile) - } - - private fun JavaTestDataFile.checkFileNameIsPresent(fileName: String) { - check(this.getContents().contains(fileName.removeSuffix(".java"))) { - "Expected the .java file name to be the same as the top-level declaration name (class/interface)." - } - } - - override fun getFiles(): List<TestDataFile> { - return files - } - - override fun toString(): String { - return "JavaTestData(pathToJavaSources='$pathToJavaSources', files=$files)" - } -} - diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestDataFile.kt deleted file mode 100644 index d8cc86a8..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestDataFile.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.java - -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -class JavaTestDataFile( - fullyQualifiedPackageName: String, - pathFromProjectRoot: String, -) : TestDataFile(pathFromProjectRoot = pathFromProjectRoot) { - - private var fileContents = "package $fullyQualifiedPackageName;" + System.lineSeparator().repeat(2) - - operator fun String.unaryPlus() { - fileContents += (this.trimIndent() + System.lineSeparator()) - } - - override fun getContents(): String { - return fileContents - } - - override fun toString(): String { - return "JavaTestDataFile(pathFromProjectRoot='$pathFromProjectRoot', fileContents='$fileContents')" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestProject.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestProject.kt deleted file mode 100644 index 39f0f0f6..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/java/JavaTestProject.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.java - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.javaTestProject -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestData -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestDataFile -import org.jetbrains.dokka.analysis.test.api.markdown.MdFileCreator -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker -import org.jetbrains.dokka.analysis.test.api.util.flatListOf - -/** - * @see javaTestProject for an explanation and a convenient way to construct this project - */ -class JavaTestProject : TestProject, JavaFileCreator, MdFileCreator { - - private val projectConfigurationBuilder = JavaTestConfigurationBuilder() - - private val javaSourceSet = JavaTestData(pathToJavaSources = DEFAULT_SOURCE_ROOT) - private val markdownTestData = MarkdownTestData() - - @AnalysisTestDslMarker - fun dokkaConfiguration(fillConfiguration: JavaTestConfigurationBuilder.() -> Unit) { - fillConfiguration(projectConfigurationBuilder) - } - - @AnalysisTestDslMarker - override fun javaFile(pathFromSrc: String, fillFile: JavaTestDataFile.() -> Unit) { - javaSourceSet.javaFile(pathFromSrc, fillFile) - } - - @AnalysisTestDslMarker - override fun mdFile(pathFromProjectRoot: String, fillFile: MarkdownTestDataFile.() -> Unit) { - markdownTestData.mdFile(pathFromProjectRoot, fillFile) - } - - override fun verify() { - projectConfigurationBuilder.verify() - } - - override fun getConfiguration(): TestDokkaConfiguration { - return projectConfigurationBuilder.build() - } - - override fun getTestData(): TestData { - return object : TestData { - override fun getFiles(): List<TestDataFile> { - return flatListOf( - this@JavaTestProject.javaSourceSet.getFiles(), - this@JavaTestProject.markdownTestData.getFiles() - ) - } - } - } - - override fun toString(): String { - return "JavaTestProject(" + - "projectConfigurationBuilder=$projectConfigurationBuilder, " + - "javaSourceSet=$javaSourceSet, " + - "markdownTestData=$markdownTestData" + - ")" - } - - internal companion object { - internal const val DEFAULT_SOURCE_ROOT = "/src/main/java" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmConfigurationBuilder.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmConfigurationBuilder.kt deleted file mode 100644 index a0255611..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmConfigurationBuilder.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.kotlin - -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaConfigurationBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaSourceSetBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaSourceSet -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * An implementation of [BaseTestDokkaConfigurationBuilder] specific to [KotlinJvmTestProject]. - */ -class KotlinJvmTestConfigurationBuilder : BaseTestDokkaConfigurationBuilder() { - override var moduleName: String = "kotlinJvmTestProject" - - private val kotlinSourceSetBuilder = KotlinJvmTestSourceSetBuilder() - - @AnalysisTestDslMarker - fun kotlinSourceSet(fillSourceSet: KotlinJvmTestSourceSetBuilder.() -> Unit) { - fillSourceSet(kotlinSourceSetBuilder) - } - - override fun verify() { - super.verify() - kotlinSourceSetBuilder.verify() - } - - override fun build(): TestDokkaConfiguration { - return TestDokkaConfiguration( - moduleName = moduleName, - includes = includes, - sourceSets = setOf(kotlinSourceSetBuilder.build()) - ) - } -} - -class KotlinJvmTestSourceSetBuilder : BaseTestDokkaSourceSetBuilder() { - override fun build(): TestDokkaSourceSet { - return TestDokkaSourceSet( - analysisPlatform = Platform.jvm, - sourceSetID = DokkaSourceSetID(scopeId = "project", sourceSetName = "kotlin"), - dependentSourceSets = setOf(), - sourceRoots = additionalSourceRoots + setOf(KotlinJvmTestProject.DEFAULT_SOURCE_ROOT), - classpath = additionalClasspath + setOf(getKotlinJvmStdlibJarPath()), - includes = includes, - samples = samples, - languageVersion = languageVersion, - apiVersion = apiVersion - ) - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmDependencyUtils.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmDependencyUtils.kt deleted file mode 100644 index c90e126f..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmDependencyUtils.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.kotlin - -private val lazyKotlinJvmStdlibJar by lazy { - ClassLoader.getSystemResource("kotlin/jvm/Strictfp.class") - ?.file - ?.replace("file:", "") - ?.replaceAfter(".jar", "") - ?: error("Unable to find Kotlin's JVM stdlib jar.") -} - -/** - * Returns an absolute path to the JAR file of Kotlin's standard library for the JVM platform. - * - * Example: `~/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.9.10/xx/kotlin-stdlib-1.9.10.jar` - */ -internal fun getKotlinJvmStdlibJarPath(): String { - return lazyKotlinJvmStdlibJar -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmTestProject.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmTestProject.kt deleted file mode 100644 index 178a1dc3..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/kotlin/KotlinJvmTestProject.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.kotlin - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.kotlin.KotlinTestData -import org.jetbrains.dokka.analysis.test.api.kotlin.KotlinTestDataFile -import org.jetbrains.dokka.analysis.test.api.kotlin.KtFileCreator -import org.jetbrains.dokka.analysis.test.api.kotlin.sample.KotlinSampleFileCreator -import org.jetbrains.dokka.analysis.test.api.kotlin.sample.KotlinSampleTestData -import org.jetbrains.dokka.analysis.test.api.kotlin.sample.KotlinSampleTestDataFile -import org.jetbrains.dokka.analysis.test.api.kotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestData -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestDataFile -import org.jetbrains.dokka.analysis.test.api.markdown.MdFileCreator -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker -import org.jetbrains.dokka.analysis.test.api.util.flatListOf - -/** - * @see kotlinJvmTestProject for an explanation and a convenient way to construct this project - */ -class KotlinJvmTestProject : TestProject, KtFileCreator, MdFileCreator, KotlinSampleFileCreator { - - private val projectConfigurationBuilder = KotlinJvmTestConfigurationBuilder() - - private val kotlinSourceSet = KotlinTestData(pathToKotlinSources = DEFAULT_SOURCE_ROOT) - private val markdownTestData = MarkdownTestData() - private val kotlinSampleTestData = KotlinSampleTestData() - - @AnalysisTestDslMarker - fun dokkaConfiguration(fillConfiguration: KotlinJvmTestConfigurationBuilder.() -> Unit) { - fillConfiguration(projectConfigurationBuilder) - } - - @AnalysisTestDslMarker - override fun ktFile(pathFromSrc: String, fqPackageName: String, fillFile: KotlinTestDataFile.() -> Unit) { - kotlinSourceSet.ktFile(pathFromSrc, fqPackageName, fillFile) - } - - @AnalysisTestDslMarker - override fun mdFile(pathFromProjectRoot: String, fillFile: MarkdownTestDataFile.() -> Unit) { - markdownTestData.mdFile(pathFromProjectRoot, fillFile) - } - - @AnalysisTestDslMarker - override fun sampleFile( - pathFromProjectRoot: String, - fqPackageName: String, - fillFile: KotlinSampleTestDataFile.() -> Unit - ) { - kotlinSampleTestData.sampleFile(pathFromProjectRoot, fqPackageName, fillFile) - } - - override fun verify() { - projectConfigurationBuilder.verify() - } - - override fun getConfiguration(): TestDokkaConfiguration { - return projectConfigurationBuilder.build() - } - - override fun getTestData(): TestData { - return object : TestData { - override fun getFiles(): List<TestDataFile> { - return flatListOf( - this@KotlinJvmTestProject.kotlinSourceSet.getFiles(), - this@KotlinJvmTestProject.markdownTestData.getFiles(), - this@KotlinJvmTestProject.kotlinSampleTestData.getFiles() - ) - } - } - } - - override fun toString(): String { - return "KotlinJvmTestProject(" + - "projectConfigurationBuilder=$projectConfigurationBuilder, " + - "kotlinSourceSet=$kotlinSourceSet, " + - "markdownTestData=$markdownTestData, " + - "kotlinSampleTestData=$kotlinSampleTestData" + - ")" - } - - internal companion object { - internal const val DEFAULT_SOURCE_ROOT = "/src/main/kotlin" - } -} - - diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmConfigurationBuilder.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmConfigurationBuilder.kt deleted file mode 100644 index 16af6e7d..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmConfigurationBuilder.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.mixed - -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaConfigurationBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.BaseTestDokkaSourceSetBuilder -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaSourceSet -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestProject -import org.jetbrains.dokka.analysis.test.api.jvm.kotlin.KotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.jvm.kotlin.getKotlinJvmStdlibJarPath -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * An implementation of [BaseTestDokkaConfigurationBuilder] specific to [MixedJvmTestProject]. - */ -class MixedJvmTestConfigurationBuilder : BaseTestDokkaConfigurationBuilder() { - override var moduleName: String = "mixedJvmTestProject" - - private val mixedJvmSourceSetBuilder = MixedJvmTestSourceSetBuilder() - - @AnalysisTestDslMarker - fun jvmSourceSet(fillSourceDir: MixedJvmTestSourceSetBuilder.() -> Unit) { - fillSourceDir(mixedJvmSourceSetBuilder) - } - - override fun verify() { - super.verify() - mixedJvmSourceSetBuilder.verify() - } - - override fun build(): TestDokkaConfiguration { - return TestDokkaConfiguration( - moduleName = moduleName, - includes = includes, - sourceSets = setOf(mixedJvmSourceSetBuilder.build()) - ) - } - - override fun toString(): String { - return "MixedJvmTestConfigurationBuilder(" + - "moduleName='$moduleName', " + - "jvmSourceSetBuilder=$mixedJvmSourceSetBuilder" + - ")" - } -} - -class MixedJvmTestSourceSetBuilder : BaseTestDokkaSourceSetBuilder() { - override fun build(): TestDokkaSourceSet { - return TestDokkaSourceSet( - analysisPlatform = Platform.jvm, - sourceSetID = DokkaSourceSetID(scopeId = "project", sourceSetName = "jvm"), - dependentSourceSets = setOf(), - sourceRoots = additionalSourceRoots + setOf( - KotlinJvmTestProject.DEFAULT_SOURCE_ROOT, - JavaTestProject.DEFAULT_SOURCE_ROOT - ), - classpath = additionalClasspath + setOf(getKotlinJvmStdlibJarPath()), - includes = includes, - samples = samples, - languageVersion = languageVersion, - apiVersion = apiVersion - ) - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestData.kt deleted file mode 100644 index 24889fe2..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestData.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.mixed - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaFileCreator -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestData -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestDataFile -import org.jetbrains.dokka.analysis.test.api.kotlin.KotlinTestData -import org.jetbrains.dokka.analysis.test.api.kotlin.KotlinTestDataFile -import org.jetbrains.dokka.analysis.test.api.kotlin.KtFileCreator -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker - -/** - * A container for populating and holding Kotlin and Java source code test data. - * - * This container exists so that common creation, population and verification logic - * can be reused, instead of having to implement [KtFileCreator] and [JavaFileCreator] multiple times. - * - * @see TestData - */ -class MixedJvmTestData(pathToSources: String) : TestData, KtFileCreator, JavaFileCreator { - - private val javaTestData = JavaTestData(pathToJavaSources = pathToSources) - private val kotlinJvmTestData = KotlinTestData(pathToKotlinSources = pathToSources) - - @AnalysisTestDslMarker - override fun javaFile(pathFromSrc: String, fillFile: JavaTestDataFile.() -> Unit) { - javaTestData.javaFile(pathFromSrc, fillFile) - } - - @AnalysisTestDslMarker - override fun ktFile(pathFromSrc: String, fqPackageName: String, fillFile: KotlinTestDataFile.() -> Unit) { - kotlinJvmTestData.ktFile(pathFromSrc, fqPackageName, fillFile) - } - - override fun getFiles(): List<TestDataFile> { - return javaTestData.getFiles() + kotlinJvmTestData.getFiles() - } - - override fun toString(): String { - return "MixedJvmTestData(javaTestData=$javaTestData, kotlinJvmTestData=$kotlinJvmTestData)" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestProject.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestProject.kt deleted file mode 100644 index 32b7ce0a..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/jvm/mixed/MixedJvmTestProject.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.jvm.mixed - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile -import org.jetbrains.dokka.analysis.test.api.TestProject -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.jvm.java.JavaTestProject -import org.jetbrains.dokka.analysis.test.api.jvm.kotlin.KotlinJvmTestProject -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestData -import org.jetbrains.dokka.analysis.test.api.markdown.MarkdownTestDataFile -import org.jetbrains.dokka.analysis.test.api.markdown.MdFileCreator -import org.jetbrains.dokka.analysis.test.api.mixedJvmTestProject -import org.jetbrains.dokka.analysis.test.api.util.AnalysisTestDslMarker -import org.jetbrains.dokka.analysis.test.api.util.flatListOf - -/** - * @see mixedJvmTestProject for an explanation and a convenient way to construct this project - */ -class MixedJvmTestProject : TestProject, MdFileCreator { - - private val projectConfigurationBuilder = MixedJvmTestConfigurationBuilder() - - private val kotlinSourceDirectory = MixedJvmTestData(pathToSources = KotlinJvmTestProject.DEFAULT_SOURCE_ROOT) - private val javaSourceDirectory = MixedJvmTestData(pathToSources = JavaTestProject.DEFAULT_SOURCE_ROOT) - private val markdownTestData = MarkdownTestData() - - @AnalysisTestDslMarker - fun dokkaConfiguration(fillConfiguration: MixedJvmTestConfigurationBuilder.() -> Unit) { - fillConfiguration(projectConfigurationBuilder) - } - - @AnalysisTestDslMarker - fun kotlinSourceDirectory(fillTestData: MixedJvmTestData.() -> Unit) { - fillTestData(kotlinSourceDirectory) - } - - @AnalysisTestDslMarker - fun javaSourceDirectory(fillTestData: MixedJvmTestData.() -> Unit) { - fillTestData(javaSourceDirectory) - } - - @AnalysisTestDslMarker - override fun mdFile(pathFromProjectRoot: String, fillFile: MarkdownTestDataFile.() -> Unit) { - markdownTestData.mdFile(pathFromProjectRoot, fillFile) - } - - override fun verify() { - projectConfigurationBuilder.verify() - } - - override fun getConfiguration(): TestDokkaConfiguration { - return projectConfigurationBuilder.build() - } - - override fun getTestData(): TestData { - return object : TestData { - override fun getFiles(): List<TestDataFile> { - return flatListOf( - this@MixedJvmTestProject.kotlinSourceDirectory.getFiles(), - this@MixedJvmTestProject.javaSourceDirectory.getFiles(), - this@MixedJvmTestProject.markdownTestData.getFiles() - ) - } - } - } - - override fun toString(): String { - return "MixedJvmTestProject(" + - "projectConfigurationBuilder=$projectConfigurationBuilder, " + - "kotlinSourceDirectory=$kotlinSourceDirectory, " + - "javaSourceDirectory=$javaSourceDirectory, " + - "markdownTestData=$markdownTestData" + - ")" - } -} - diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestData.kt deleted file mode 100644 index 02911235..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestData.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -/** - * A container for populating and holding Kotlin source code test data. - * - * This container exists so that common creation, population and verification logic - * can be reused, instead of having to implement [KtFileCreator] multiple times. - * - * @param pathToKotlinSources path to the `src` directory in which Kotlin sources must reside. - * Must be relative to the root of the test project. Example: `/src/main/kotlin` - * @see TestData - */ -class KotlinTestData( - private val pathToKotlinSources: String -) : TestData, KtFileCreator { - - private val files = mutableListOf<TestDataFile>() - - override fun ktFile( - pathFromSrc: String, - fqPackageName: String, - fillFile: KotlinTestDataFile.() -> Unit - ) { - check(pathFromSrc.endsWith(".kt")) { "Kotlin files are expected to have .kt extension" } - - val testDataFile = KotlinTestDataFile( - pathFromProjectRoot = "$pathToKotlinSources/$pathFromSrc", - fqPackageName = fqPackageName, - ) - fillFile(testDataFile) - files.add(testDataFile) - } - - override fun getFiles(): List<TestDataFile> { - return files - } - - override fun toString(): String { - return "KotlinTestData(pathToKotlinSources='$pathToKotlinSources', files=$files)" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestDataFile.kt deleted file mode 100644 index 355440e7..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KotlinTestDataFile.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin - -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -class KotlinTestDataFile( - pathFromProjectRoot: String, - fqPackageName: String, -) : TestDataFile(pathFromProjectRoot = pathFromProjectRoot) { - - private var fileContents = "package $fqPackageName" + System.lineSeparator().repeat(2) - - operator fun String.unaryPlus() { - fileContents += (this.trimIndent() + System.lineSeparator()) - } - - override fun getContents(): String { - return fileContents - } - - override fun toString(): String { - return "KotlinTestDataFile(pathFromProjectRoot='$pathFromProjectRoot', fileContents='$fileContents')" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KtFileCreator.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KtFileCreator.kt deleted file mode 100644 index 15ce31ce..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/KtFileCreator.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin - -import org.jetbrains.dokka.analysis.test.api.util.filePathToPackageName - -/** - * Declares a capability that a `.kt` file can be created in the scope of the implementation. - */ -interface KtFileCreator { - - /** - * Creates a `.kt` file. - * - * By default, the package of this file is deduced automatically from the [pathFromSrc] param. - * For example, for a path `org/jetbrains/dokka/test` the package will be `org.jetbrains.dokka.test`. - * The package can be overridden by setting [fqPackageName]. - * - * @param pathFromSrc path relative to the source code directory of the project. - * Must contain packages (if any) and end in `.kt`. - * Example: `org/jetbrains/dokka/test/File.kt` - * @param fqPackageName package name to be used in the `package` statement of this file. - * This value overrides the automatically deduced package. - */ - fun ktFile( - pathFromSrc: String, - fqPackageName: String = filePathToPackageName(pathFromSrc), - fillFile: KotlinTestDataFile.() -> Unit - ) -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleFileCreator.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleFileCreator.kt deleted file mode 100644 index 7fa1d28d..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleFileCreator.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin.sample - -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaSourceSet - -/** - * Declares a capability that a `.kt` file can be created that will be used as a usage sample. - */ -interface KotlinSampleFileCreator { - - /** - * Creates a `.kt` file outside of the source code directory. It should be used as input - * for the `@sample` KDoc tag. - * - * To be picked by Dokka, this file must be included in [TestDokkaSourceSet.samples]. - * - * @param pathFromProjectRoot path relative to the root of the test project. Must begin - * with `/` to not confuse it with relative paths. Example: `/samples/collections.kt` - * @param fqPackageName fully qualified package name to be used in the `package` statement of the file. - * This parameter must be set because the package name cannot be deduced - * from the file path, as samples usually reside outside of the source code directory. - * Example: `org.jetbrains.dokka.sample.collections` - */ - fun sampleFile( - pathFromProjectRoot: String, - fqPackageName: String, - fillFile: KotlinSampleTestDataFile.() -> Unit - ) -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestData.kt deleted file mode 100644 index 9ba4187c..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestData.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin.sample - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -/** - * A container for populating and holding Kotlin sample test data. - * - * This container exists so that common creation, population and verification logic - * can be reused, instead of having to implement [KotlinSampleFileCreator] multiple times. - * - * @see TestData - */ -class KotlinSampleTestData : TestData, KotlinSampleFileCreator { - - private val files = mutableListOf<TestDataFile>() - - override fun sampleFile( - pathFromProjectRoot: String, - fqPackageName: String, - fillFile: KotlinSampleTestDataFile.() -> Unit - ) { - check(pathFromProjectRoot.endsWith(".kt")) { "Kotlin sample files are expected to have .kt extension" } - - val testDataFile = KotlinSampleTestDataFile( - pathFromProjectRoot = pathFromProjectRoot, - fqPackageName = fqPackageName - ) - fillFile(testDataFile) - files.add(testDataFile) - } - - override fun getFiles(): List<TestDataFile> { - return files - } - - override fun toString(): String { - return "KotlinSampleTestData(files=$files)" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestDataFile.kt deleted file mode 100644 index 6dc8230b..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/kotlin/sample/KotlinSampleTestDataFile.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.kotlin.sample - -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -class KotlinSampleTestDataFile( - pathFromProjectRoot: String, - fqPackageName: String, -) : TestDataFile(pathFromProjectRoot = pathFromProjectRoot) { - - private var fileContents = "package $fqPackageName" + System.lineSeparator().repeat(2) - - operator fun String.unaryPlus() { - fileContents += (this.trimIndent() + System.lineSeparator()) - } - - override fun getContents(): String { - return fileContents - } - - override fun toString(): String { - return "KotlinSampleTestDataFile(pathFromProjectRoot='$pathFromProjectRoot', fileContents='$fileContents')" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestData.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestData.kt deleted file mode 100644 index d0cb64fb..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestData.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.markdown - -import org.jetbrains.dokka.analysis.test.api.TestData -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -/** - * A container for populating and holding Markdown test data. - * - * This container exists so that common creation, population and verification logic - * can be reused, instead of having to implement [MdFileCreator] multiple times. - * - * @see TestData - */ -class MarkdownTestData : TestData, MdFileCreator { - - private val files = mutableListOf<TestDataFile>() - - override fun mdFile( - pathFromProjectRoot: String, - fillFile: MarkdownTestDataFile.() -> Unit - ) { - check(pathFromProjectRoot.endsWith(".md")) { "Markdown files are expected to have .md extension" } - - val testDataFile = MarkdownTestDataFile(pathFromProjectRoot) - fillFile(testDataFile) - files.add(testDataFile) - } - - override fun getFiles(): List<TestDataFile> { - return files - } - - override fun toString(): String { - return "MarkdownTestData(files=$files)" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestDataFile.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestDataFile.kt deleted file mode 100644 index 9bb8169a..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MarkdownTestDataFile.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.markdown - -import org.jetbrains.dokka.analysis.test.api.TestDataFile - -class MarkdownTestDataFile( - pathFromProjectRoot: String -) : TestDataFile(pathFromProjectRoot = pathFromProjectRoot) { - - private var fileContents = "" - - operator fun String.unaryPlus() { - fileContents += (this.trimIndent() + System.lineSeparator()) - } - - override fun getContents(): String { - return fileContents - } - - override fun toString(): String { - return "MarkdownTestDataFile(pathFromProjectRoot='$pathFromProjectRoot', fileContents='$fileContents')" - } -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MdFileCreator.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MdFileCreator.kt deleted file mode 100644 index 8ba97b17..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/markdown/MdFileCreator.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.markdown - -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaConfiguration -import org.jetbrains.dokka.analysis.test.api.configuration.TestDokkaSourceSet - -/** - * Declares a capability that an `.md` file can be created in the scope of the implementation. - */ -interface MdFileCreator { - - /** - * Creates an `.md` (Markdown) file. - * - * If you want to use this file for module and package documentation, it must be included - * in [TestDokkaConfiguration.includes] or [TestDokkaSourceSet.includes]. - * - * @param pathFromProjectRoot path relative to the root of the test project. Must begin - * with `/` to not confuse it with relative paths. Example: `/docs/core-package.md` - */ - fun mdFile( - pathFromProjectRoot: String, - fillFile: MarkdownTestDataFile.() -> Unit - ) -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/CollectionUtils.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/CollectionUtils.kt deleted file mode 100644 index 6cd41594..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/CollectionUtils.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.util - -internal inline fun <reified T> flatListOf(vararg lists: List<T>): List<T> { - val overallSize = lists.sumBy { it.size } - val aggregatingList = ArrayList<T>(overallSize) - lists.forEach { - aggregatingList.addAll(it) - } - return aggregatingList -} - -internal inline fun <T, R> Iterable<T>.mapToSet(transform: (T) -> R): Set<R> { - return this.map(transform).toSet() -} diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/DslApiUtils.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/DslApiUtils.kt deleted file mode 100644 index e855bb4b..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/DslApiUtils.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.util - -@DslMarker -@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) -annotation class AnalysisTestDslMarker diff --git a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt b/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt deleted file mode 100644 index 779add8d..00000000 --- a/subprojects/analysis-kotlin-api/src/testFixtures/kotlin/org/jetbrains/dokka/analysis/test/api/util/FileUtils.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.test.api.util - -import org.jetbrains.dokka.utilities.DokkaLogger -import java.io.File -import java.io.IOException - -/** - * Converts a file path (like `org/jetbrains/dokka/test/File.kt`) to a fully qualified - * package name (like `org.jetbrains.dokka.test`). - * - * @param srcRelativeFilePath path relative to the source code directory. If the full path of the file - * is `src/main/kotlin/org/jetbrains/dokka/test/File.kt`, then only - * `org/jetbrains/dokka/test/File.kt` is expected to be passed here. - * @return fully qualified package name or an empty string in case of the root package. - */ -internal fun filePathToPackageName(srcRelativeFilePath: String): String { - return srcRelativeFilePath - .substringBeforeLast("/", missingDelimiterValue = "") - .replace("/", ".") -} - -/** - * @throws IOException if the requested temporary directory could not be created or deleted once used. - */ -internal fun <T> withTempDirectory(logger: DokkaLogger? = null, block: (tempDirectory: File) -> T): T { - @Suppress("DEPRECATION") // TODO migrate to kotlin.io.path.createTempDirectory with languageVersion >= 1.5 - val tempDir = createTempDir() - try { - logger?.debug("Created temporary directory $tempDir") - return block(tempDir) - } finally { - if (!tempDir.deleteRecursively()) { - throw IOException("Unable to delete temporary directory $tempDir") - } - logger?.debug("Deleted temporary directory $tempDir") - } -} diff --git a/subprojects/analysis-kotlin-descriptors/README.md b/subprojects/analysis-kotlin-descriptors/README.md deleted file mode 100644 index fbfd1c8b..00000000 --- a/subprojects/analysis-kotlin-descriptors/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Analysis: Kotlin descriptors - -An internal descriptor-based implementation for [analysis-kotlin-api](../analysis-kotlin-api), also known as K1 or -"the old compiler". - -Contains no stable public API and must not be used by anyone directly, only via [analysis-kotlin-api](../analysis-kotlin-api). - -Can be added as a runtime dependency by the runner. diff --git a/subprojects/analysis-kotlin-descriptors/api/analysis-kotlin-descriptors.api b/subprojects/analysis-kotlin-descriptors/api/analysis-kotlin-descriptors.api deleted file mode 100644 index e69de29b..00000000 --- a/subprojects/analysis-kotlin-descriptors/api/analysis-kotlin-descriptors.api +++ /dev/null diff --git a/subprojects/analysis-kotlin-descriptors/build.gradle.kts b/subprojects/analysis-kotlin-descriptors/build.gradle.kts deleted file mode 100644 index 9690ea6b..00000000 --- a/subprojects/analysis-kotlin-descriptors/build.gradle.kts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -import org.jetbrains.DokkaPublicationBuilder -import org.jetbrains.registerDokkaArtifactPublication - -plugins { - id("org.jetbrains.conventions.kotlin-jvm") - id("org.jetbrains.conventions.maven-publish") - id("com.github.johnrengelman.shadow") -} - -dependencies { - // to override some interfaces (JvmAnnotationEnumFieldValue, JvmAnnotationConstantValue) from compiler since thet are empty there - // should be `api` since we already have it in :analysis-java-psi - api(libs.intellij.java.psi.api) { - isTransitive = false - } - implementation(projects.subprojects.analysisKotlinApi) - implementation(projects.subprojects.analysisKotlinDescriptors.compiler) - implementation(projects.subprojects.analysisKotlinDescriptors.ide) -} - -tasks { - // There are several reasons for shadowing all dependencies in one place: - // 1. Some of the artifacts Dokka depends on, like com.jetbrains.intellij.java:java-psi, are not - // published to Maven Central, so the users would need to add custom repositories to their build scripts. - // 2. There are many intertwining transitive dependencies of different versions, as well as direct copy-paste, - // that can lead to runtime errors due to classpath conflicts, so it's best to let Gradle take care of - // dependency resolution, and then pack everything into a single jar in a single place that can be tuned. - // 3. The compiler and ide modules are internal details that are likely to change, so packing everything into - // a single jar provides some stability for the CLI users, while not exposing too many internals. Publishing - // the compiler, ide and other subprojects separately would make it difficult to refactor the project structure. - shadowJar { - val dokka_version: String by project - - // cannot be named exactly like the artifact (i.e analysis-kotlin-descriptors-VER.jar), - // otherwise leads to obscure test failures when run via CLI, but not via IJ - archiveFileName.set("analysis-kotlin-descriptors-all-$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("analysisKotlinDescriptors") { - artifactId = "analysis-kotlin-descriptors" - component = DokkaPublicationBuilder.Component.Shadow -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/README.md b/subprojects/analysis-kotlin-descriptors/compiler/README.md deleted file mode 100644 index 5676fbf2..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Descriptors: compiler - -An internal module that encapsulates external compiler (`org.jetbrains.kotlin:kotlin-compiler`) dependencies. - -Parses Kotlin sources. - -Exists primarily to make sure that unreliable and coupled external dependencies are somewhat abstracted away, -otherwise everything gets tangled together and breaking changes in such dependencies become very -difficult to resolve. diff --git a/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api b/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api deleted file mode 100644 index 373ec268..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/api/compiler.api +++ /dev/null @@ -1,126 +0,0 @@ -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 <init> ()V - public final fun getAnalysisContextCreator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getCompilerExtensionPointProvider ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; - public final fun getDescriptorFinder ()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 getKotlinSampleProviderFactory ()Lorg/jetbrains/dokka/plugability/Extension; - public final fun getMockApplicationHack ()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 <init> (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/DescriptorFinder { - 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/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/library/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/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 <init> (Lorg/jetbrains/kotlin/cli/common/messages/MessageCollector;Lorg/jetbrains/dokka/Platform;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack;Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService;)V - public fun dispose ()V -} - -public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration : org/jetbrains/dokka/plugability/ConfigurableBlock { - public static final field Companion Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration$Companion; - public static final field DEFAULT_IGNORE_COMMON_BUILT_INS Z - public fun <init> ()V - public fun <init> (Z)V - public synthetic fun <init> (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Z - public final fun copy (Z)Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration;ZILjava/lang/Object;)Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration; - public fun equals (Ljava/lang/Object;)Z - public final fun getIgnoreCommonBuiltIns ()Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DokkaAnalysisConfiguration$Companion { -} - -public abstract class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis : java/io/Closeable { - public fun <init> ()V - public fun <init> (Lorg/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis;)V - public synthetic fun <init> (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; -} - -public class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/KotlinSampleProvider : org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider { - public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public fun close ()V - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; - public fun getSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet; - protected fun processBody (Lcom/intellij/psi/PsiElement;)Ljava/lang/String; - protected fun processImports (Lcom/intellij/psi/PsiElement;)Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/KotlinSampleProviderFactory : org/jetbrains/dokka/analysis/kotlin/internal/SampleProviderFactory { - public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public fun build ()Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider; - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; -} - -public final class org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl : com/intellij/core/CoreJavaFileManager, org/jetbrains/kotlin/resolve/jvm/KotlinCliJavaFileManager { - public static final field Companion Lorg/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl$Companion; - public fun <init> (Lcom/intellij/psi/PsiManager;)V - public fun findClass (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)Lcom/intellij/psi/PsiClass; - public fun findClass (Lorg/jetbrains/kotlin/load/java/JavaClassFinder$Request;Lcom/intellij/psi/search/GlobalSearchScope;)Lorg/jetbrains/kotlin/load/java/structure/JavaClass; - public final fun findClass (Lorg/jetbrains/kotlin/name/ClassId;Lcom/intellij/psi/search/GlobalSearchScope;)Lorg/jetbrains/kotlin/load/java/structure/JavaClass; - public fun findClasses (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)[Lcom/intellij/psi/PsiClass; - public fun findModules (Ljava/lang/String;Lcom/intellij/psi/search/GlobalSearchScope;)Ljava/util/Collection; - public fun findPackage (Ljava/lang/String;)Lcom/intellij/psi/PsiPackage; - public fun getNonTrivialPackagePrefixes ()Ljava/util/Collection; - public final fun initialize (Lorg/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndex;Ljava/util/List;Lorg/jetbrains/kotlin/cli/jvm/index/SingleJavaFileRootsIndex;Z)V - public fun knownClassNamesInPackage (Lorg/jetbrains/kotlin/name/FqName;)Ljava/util/Set; -} - -public final class org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl$Companion { -} - -public final class org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl : org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndex { - public fun <init> (Ljava/util/List;)V - public fun findClass (Lorg/jetbrains/kotlin/name/ClassId;Ljava/util/Set;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public fun getIndexedRoots ()Lkotlin/sequences/Sequence; - public fun traverseDirectoriesInPackage (Lorg/jetbrains/kotlin/name/FqName;Ljava/util/Set;Lkotlin/jvm/functions/Function2;)V -} - diff --git a/subprojects/analysis-kotlin-descriptors/compiler/build.gradle.kts b/subprojects/analysis-kotlin-descriptors/compiler/build.gradle.kts deleted file mode 100644 index d9e8dd75..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/build.gradle.kts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -plugins { - id("org.jetbrains.conventions.kotlin-jvm") -} - -dependencies { - compileOnly(projects.core) - compileOnly(projects.subprojects.analysisKotlinApi) - - api(libs.kotlin.compiler) - - implementation(projects.subprojects.analysisMarkdownJb) - implementation(projects.subprojects.analysisJavaPsi) - - testImplementation(kotlin("test")) - testImplementation(projects.core.contentMatcherTestUtils) - testImplementation(projects.core.testApi) - - // TODO [beresnev] get rid of it - compileOnly(libs.kotlinx.coroutines.core) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/AnalysisContextCreator.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/AnalysisContextCreator.kt deleted file mode 100644 index 67476a50..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/AnalysisContextCreator.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import com.intellij.mock.MockProject -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment -import org.jetbrains.kotlin.analyzer.ResolverForModule -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.descriptors.ModuleDescriptor - -@InternalDokkaApi -public interface AnalysisContextCreator { - public fun create( - project: MockProject, - moduleDescriptor: ModuleDescriptor, - moduleResolver: ResolverForModule, - kotlinEnvironment: KotlinCoreEnvironment, - analysisEnvironment: AnalysisEnvironment, - ): AnalysisContext -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt deleted file mode 100644 index c59a43b2..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDescriptorAnalysisPlugin.kt +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute -import com.intellij.psi.PsiAnnotation -import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.java.BreakingAbstractionKotlinLightMethodChecker -import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.DokkaAnalysisConfiguration -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.KotlinAnalysis -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.ProjectKotlinAnalysis -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.renderers.PostAction -import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProviderFactory -import org.jetbrains.dokka.plugability.* -import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation - -@Suppress("unused") -@InternalDokkaApi -public class CompilerDescriptorAnalysisPlugin : DokkaPlugin() { - - @InternalDokkaApi - public val kdocFinder: ExtensionPoint<KDocFinder> by extensionPoint() - - @InternalDokkaApi - public val descriptorFinder: ExtensionPoint<DescriptorFinder> by extensionPoint() - - @InternalDokkaApi - public val klibService: ExtensionPoint<KLibService> by extensionPoint() - - @InternalDokkaApi - public val compilerExtensionPointProvider: ExtensionPoint<CompilerExtensionPointProvider> by extensionPoint() - - @InternalDokkaApi - public val mockApplicationHack: ExtensionPoint<MockApplicationHack> by extensionPoint() - - @InternalDokkaApi - public val analysisContextCreator: ExtensionPoint<AnalysisContextCreator> by extensionPoint() - - @InternalDokkaApi - public val kotlinAnalysis: ExtensionPoint<KotlinAnalysis> by extensionPoint() - - internal val documentableAnalyzerImpl by extending { - plugin<InternalKotlinAnalysisPlugin>().documentableSourceLanguageParser providing { CompilerDocumentableSourceLanguageParser() } - } - - internal val defaultKotlinAnalysis by extending { - @OptIn(DokkaPluginApiPreview::class) - kotlinAnalysis providing { ctx -> - val configuration = configuration<CompilerDescriptorAnalysisPlugin, DokkaAnalysisConfiguration>(ctx) - ?: DokkaAnalysisConfiguration() - ProjectKotlinAnalysis( - sourceSets = ctx.configuration.sourceSets, - context = ctx, - analysisConfiguration = configuration - ) - } - } - - internal val descriptorToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator providing ::DefaultDescriptorToDocumentableTranslator - } - - - internal val descriptorFullClassHierarchyBuilder by extending { - plugin<InternalKotlinAnalysisPlugin>().fullClassHierarchyBuilder providing { DescriptorFullClassHierarchyBuilder() } - } - - /** - * StdLib has its own a sample provider - * So it should have a possibility to override this extension - */ - @InternalDokkaApi - public val kotlinSampleProviderFactory: Extension<SampleProviderFactory, *, *> by extending { - plugin<InternalKotlinAnalysisPlugin>().sampleProviderFactory providing ::KotlinSampleProviderFactory - } - - internal val descriptorSyntheticDocumentableDetector by extending { - plugin<InternalKotlinAnalysisPlugin>().syntheticDocumentableDetector providing { DescriptorSyntheticDocumentableDetector() } - } - - internal val moduleAndPackageDocumentationReader by extending { - plugin<InternalKotlinAnalysisPlugin>().moduleAndPackageDocumentationReader providing ::ModuleAndPackageDocumentationReader - } - - internal val kotlinToJavaMapper by extending { - plugin<InternalKotlinAnalysisPlugin>().kotlinToJavaService providing { DescriptorKotlinToJavaMapper() } - } - - internal val descriptorInheritanceBuilder by extending { - plugin<InternalKotlinAnalysisPlugin>().inheritanceBuilder providing { DescriptorInheritanceBuilder() } - } - - internal val defaultExternalDocumentablesProvider by extending { - plugin<InternalKotlinAnalysisPlugin>().externalDocumentablesProvider providing ::DefaultExternalDocumentablesProvider - } - - private val javaAnalysisPlugin by lazy { plugin<JavaAnalysisPlugin>() } - - 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 { - DescriptorKotlinDocCommentCreator(querySingle { kdocFinder }, querySingle { descriptorFinder }) - } - } - - internal val kotlinDocCommentParser by extending { - javaAnalysisPlugin.docCommentParsers providing { context -> - DescriptorKotlinDocCommentParser( - 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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDocumentableSourceLanguageParser.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDocumentableSourceLanguageParser.kt deleted file mode 100644 index 2dbc242a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerDocumentableSourceLanguageParser.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource -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.dokka.analysis.kotlin.internal.DocumentableLanguage -import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableSourceLanguageParser - -internal class CompilerDocumentableSourceLanguageParser : DocumentableSourceLanguageParser { - 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}") - } - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider.kt deleted file mode 100644 index e42efe41..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/CompilerExtensionPointProvider.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor - -@InternalDokkaApi -public interface CompilerExtensionPointProvider { - public fun get(): List<CompilerExtensionPoint> - - public class CompilerExtensionPoint( - public val extensionDescriptor: ApplicationExtensionDescriptor<Any>, - public val extensions: List<Any> - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/DescriptorFinder.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/DescriptorFinder.kt deleted file mode 100644 index db06647d..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/DescriptorFinder.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.psi.KtDeclaration - -@InternalDokkaApi -public interface DescriptorFinder { - public fun KtDeclaration.findDescriptor(): DeclarationDescriptor? -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder.kt deleted file mode 100644 index e5367211..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KDocFinder.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils - -@InternalDokkaApi -public interface KDocFinder { - public fun KtElement.findKDoc(): KDocTag? - - public fun DeclarationDescriptor.find( - descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { - DescriptorToSourceUtils.descriptorToDeclaration( - it - ) - } - ): KDocTag? - - public fun resolveKDocLink( - fromDescriptor: DeclarationDescriptor, - qualifiedName: String, - sourceSet: DokkaConfiguration.DokkaSourceSet, - emptyBindingContext: Boolean = false - ): Collection<DeclarationDescriptor> -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService.kt deleted file mode 100644 index fc173298..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/KLibService.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.kotlin.library.metadata.KlibMetadataModuleDescriptorFactory -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.storage.StorageManager - -@InternalDokkaApi -public interface KLibService { - public fun KotlinLibrary.createPackageFragmentProvider( - storageManager: StorageManager, - metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory, - languageVersionSettings: LanguageVersionSettings, - moduleDescriptor: ModuleDescriptor, - lookupTracker: LookupTracker - ): PackageFragmentProvider? - - public fun isAnalysisCompatible(kotlinLibrary: KotlinLibrary): Boolean -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack.kt deleted file mode 100644 index 39ca666b..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/MockApplicationHack.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler - -import com.intellij.mock.MockApplication -import org.jetbrains.dokka.InternalDokkaApi - -@InternalDokkaApi -public interface MockApplicationHack { // ¯\_(ツ)_/¯ - public fun hack(mockApplication: MockApplication) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt deleted file mode 100644 index 8cf05053..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AbsolutePathString.kt +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -internal typealias AbsolutePathString = String diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt deleted file mode 100644 index 917a86e7..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisContext.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -import com.intellij.openapi.project.Project -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -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.DokkaPluginApiPreview -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 - -@OptIn(DokkaPluginApiPreview::class) -internal fun createAnalysisContext( - context: DokkaContext, - sourceSets: List<DokkaConfiguration.DokkaSourceSet>, - sourceSet: DokkaConfiguration.DokkaSourceSet, - analysisConfiguration: DokkaAnalysisConfiguration -): AnalysisContext { - val parentSourceSets = sourceSets.filter { it.sourceSetID in sourceSet.dependentSourceSets } - val classpath = sourceSet.classpath + parentSourceSets.flatMap { it.classpath } - val sources = sourceSet.sourceRoots + parentSourceSets.flatMap { it.sourceRoots } - - return createAnalysisContext( - context = context, - classpath = classpath, - sourceRoots = sources, - sourceSet = sourceSet, - analysisConfiguration = analysisConfiguration - ) -} - -@OptIn(DokkaPluginApiPreview::class) -internal fun createAnalysisContext( - context: DokkaContext, - classpath: List<File>, - sourceRoots: Set<File>, - sourceSet: DokkaConfiguration.DokkaSourceSet, - analysisConfiguration: DokkaAnalysisConfiguration -): AnalysisContext { - val analysisEnvironment = AnalysisEnvironment( - DokkaMessageCollector(context.logger), - sourceSet.analysisPlatform, - context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { mockApplicationHack }, - context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { klibService }, - ).apply { - if (analysisPlatform == Platform.jvm) { - configureJdkClasspathRoots() - } - addClasspath(classpath) - addSources(sourceRoots) - - loadLanguageVersionSettings(sourceSet.languageVersion, sourceSet.apiVersion) - } - - val environment = analysisEnvironment.createCoreEnvironment() - return analysisEnvironment.createResolutionFacade( - environment, - context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle<CompilerDescriptorAnalysisPlugin, AnalysisContextCreator> { analysisContextCreator }, - analysisConfiguration.ignoreCommonBuiltIns - ) -} - -internal class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector { - override fun clear() { - seenErrors = false - } - - private var seenErrors = false - - override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) { - if (severity == CompilerMessageSeverity.ERROR) { - seenErrors = true - } - logger.info(MessageRenderer.PLAIN_FULL_PATHS.render(severity, message, location)) - } - - override fun hasErrors() = seenErrors -} - -@InternalDokkaApi -public interface AnalysisContext : Closeable { - public val environment: KotlinCoreEnvironment - public val resolveSession: ResolveSession - public val moduleDescriptor: ModuleDescriptor - public val project: Project -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt deleted file mode 100644 index 5a0fc396..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/AnalysisEnvironment.kt +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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 -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Disposer -import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.psi.PsiNameHelper -import com.intellij.psi.impl.PsiNameHelperImpl -import com.intellij.psi.impl.source.javadoc.JavadocManagerImpl -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.kotlin.descriptors.compiler.AnalysisContextCreator -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.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.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.config.ContentRoot -import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot -import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM -import org.jetbrains.kotlin.cli.jvm.config.* -import org.jetbrains.kotlin.cli.jvm.index.JavaRoot -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.context.ProjectContext -import org.jetbrains.kotlin.context.withModule -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.js.config.JSConfigurationKeys -import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices -import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy -import org.jetbrains.kotlin.library.resolveSingleFileKlib -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.TargetPlatform -import org.jetbrains.kotlin.platform.js.JsPlatforms -import org.jetbrains.kotlin.platform.jvm.JvmPlatforms -import org.jetbrains.kotlin.platform.jvm.JvmPlatforms.unspecifiedJvmPlatform -import org.jetbrains.kotlin.platform.konan.NativePlatforms -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.CliSealedClassInheritorsProvider -import org.jetbrains.kotlin.resolve.CompilerEnvironment -import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices -import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters -import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices -import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices -import org.jetbrains.kotlin.storage.LockBasedStorageManager -import java.io.File -import org.jetbrains.kotlin.konan.file.File as KFile - -internal const val JAR_SEPARATOR = "!/" - -/** - * Kotlin as a service entry point - * - * Configures environment, analyses files and provides facilities to perform code processing without emitting bytecode - * - * $messageCollector: required by compiler infrastructure and will receive all compiler messages - * $body: optional and can be used to configure environment without creating local variable - */ -@InternalDokkaApi -public class AnalysisEnvironment( - private val messageCollector: MessageCollector, - internal val analysisPlatform: Platform, - private val mockApplicationHack: MockApplicationHack, - private val kLibService: KLibService, -) : Disposable { - private val configuration = CompilerConfiguration() - - init { - configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) - } - - internal fun createCoreEnvironment(): KotlinCoreEnvironment { - System.setProperty("idea.io.use.nio2", "true") - System.setProperty("idea.ignore.disabled.plugins", "true") - - val configFiles = when (analysisPlatform) { - Platform.jvm, Platform.common -> EnvironmentConfigFiles.JVM_CONFIG_FILES - Platform.native -> EnvironmentConfigFiles.NATIVE_CONFIG_FILES - Platform.js, Platform.wasm -> EnvironmentConfigFiles.JS_CONFIG_FILES - } - - val environment = KotlinCoreEnvironment.createForProduction(this, configuration, configFiles) - val projectComponentManager = environment.project as MockComponentManager - - CoreApplicationEnvironment.registerExtensionPoint( - environment.project.extensionArea, - JavadocTagInfo.EP_NAME, JavadocTagInfo::class.java - ) - - @Suppress("DEPRECATION") - val extensionArea = Extensions.getRootArea() - - CoreApplicationEnvironment.registerExtensionPoint( - extensionArea, - CustomJavadocTagProvider.EP_NAME, CustomJavadocTagProvider::class.java - ) - - // TODO: figure out why compilation fails with unresolved `CoreApplicationEnvironment.registerApplicationService(...)` - // call, fix it appropriately - with(ApplicationManager.getApplication() as MockApplication) { - mockApplicationHack.hack(this) - } - - projectComponentManager.registerService( - JavadocManager::class.java, - JavadocManagerImpl(environment.project) - ) - - projectComponentManager.registerService( - PsiNameHelper::class.java, - PsiNameHelperImpl(environment.project) - ) - - projectComponentManager.registerService( - CustomJavadocTagProvider::class.java, - CustomJavadocTagProvider { emptyList() } - ) - - return environment - } - - private fun createSourceModuleSearchScope(project: Project, sourceFiles: List<KtFile>): GlobalSearchScope = - when (analysisPlatform) { - Platform.jvm -> TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, sourceFiles) - Platform.js, Platform.common, Platform.native, Platform.wasm -> GlobalSearchScope.filesScope( - project, - sourceFiles.map { it.virtualFile }.toSet() - ) - } - - internal fun createResolutionFacade( - environment: KotlinCoreEnvironment, - analysisContextCreator: AnalysisContextCreator, - ignoreCommonBuiltIns: Boolean = false - ): AnalysisContext { - val projectContext = ProjectContext(environment.project, "Dokka") - val sourceFiles = environment.getSourceFiles() - - val targetPlatform = when (analysisPlatform) { - Platform.js, Platform.wasm -> JsPlatforms.defaultJsPlatform - Platform.common -> CommonPlatforms.defaultCommonPlatform - Platform.native -> NativePlatforms.unspecifiedNativePlatform - Platform.jvm -> JvmPlatforms.defaultJvmPlatform - } - - val kotlinLibraries: Map<AbsolutePathString, KotlinLibrary> = resolveKotlinLibraries() - - val commonDependencyContainer = if (analysisPlatform == Platform.common) DokkaKlibMetadataCommonDependencyContainer( - kotlinLibraries.values.toList(), - environment.configuration, - LockBasedStorageManager("DokkaKlibMetadata") - ) else null - - val extraModuleDependencies = kotlinLibraries.values.registerLibraries() + commonDependencyContainer?.moduleInfos.orEmpty() - - val library = object : LibraryModuleInfo { - override val analyzerServices: PlatformDependentAnalyzerServices = - analysisPlatform.analyzerServices() - override val name: Name = Name.special("<library>") - override val platform: TargetPlatform = targetPlatform - override fun dependencies(): List<ModuleInfo> = listOf(this) - override fun getLibraryRoots(): Collection<String> = classpath - .map { libraryFile -> libraryFile.absolutePath } - .filter { path -> path !in kotlinLibraries } - } - - val module = object : ModuleInfo { - override val analyzerServices: PlatformDependentAnalyzerServices = - analysisPlatform.analyzerServices() - override val name: Name = Name.special("<module>") - override val platform: TargetPlatform = targetPlatform - override fun dependencies(): List<ModuleInfo> = - listOf(this, library) + extraModuleDependencies - - /** - * Only for common platform ignore BuiltIns for StdLib since it can cause a conflict - * between BuiltIns from a compiler and ones from source code. - */ - override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns { - return if (analysisPlatform == Platform.common && ignoreCommonBuiltIns) ModuleInfo.DependencyOnBuiltIns.NONE - else super.dependencyOnBuiltIns() - } - } - - val sourcesScope = createSourceModuleSearchScope(environment.project, sourceFiles) - val modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo> = { - when (it) { - library -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) - module -> ModuleContent(it, emptyList(), GlobalSearchScope.allScope(environment.project)) - is DokkaKlibLibraryInfo -> { - if (it.libraryRoot in kotlinLibraries) - ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) - else null - } - is CommonKlibModuleInfo -> ModuleContent(it, emptyList(), GlobalSearchScope.notScope(sourcesScope)) - else -> null - } ?: throw IllegalArgumentException("Unexpected module info") - } - - var builtIns: JvmBuiltIns? = null - - val resolverForProject = when (analysisPlatform) { - Platform.jvm -> { - builtIns = JvmBuiltIns( - projectContext.storageManager, - JvmBuiltIns.Kind.FROM_CLASS_LOADER - ) // TODO we should use FROM_DEPENDENCIES - createJvmResolverForProject( - projectContext, - module, - library, - modulesContent, - sourcesScope, - builtIns - ) - } - Platform.common -> createCommonResolverForProject( - projectContext, - module, - modulesContent, - environment, - commonDependencyContainer - ) - Platform.js, Platform.wasm -> createJsResolverForProject(projectContext, module, modulesContent) - 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) - - @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) - - return analysisContextCreator.create( - environment.project as MockProject, - moduleDescriptor, - resolverForModule, - environment, - this - ) - } - - private fun Platform.analyzerServices() = when (this) { - Platform.js, Platform.wasm -> JsPlatformAnalyzerServices - Platform.common -> CommonPlatformAnalyzerServices - Platform.native -> NativePlatformAnalyzerServices - Platform.jvm -> JvmPlatformAnalyzerServices - } - - private fun Collection<KotlinLibrary>.registerLibraries(): List<DokkaKlibLibraryInfo> { - if (analysisPlatform != Platform.native && analysisPlatform != Platform.js && analysisPlatform != Platform.wasm) return emptyList() - val dependencyResolver = DokkaKlibLibraryDependencyResolver() - val analyzerServices = analysisPlatform.analyzerServices() - - return map { kotlinLibrary -> - if (analysisPlatform == org.jetbrains.dokka.Platform.native) DokkaNativeKlibLibraryInfo( - kotlinLibrary, - analyzerServices, - dependencyResolver - ) - else DokkaJsKlibLibraryInfo(kotlinLibrary, analyzerServices, dependencyResolver) - } - } - - @OptIn(ExperimentalStdlibApi::class) - private fun resolveKotlinLibraries(): Map<AbsolutePathString, KotlinLibrary> { - return if (analysisPlatform == Platform.jvm) emptyMap() else buildMap { - classpath - .filter { it.isDirectory || it.extension == KLIB_FILE_EXTENSION } - .forEach { libraryFile -> - try { - val kotlinLibrary = resolveSingleFileKlib( - libraryFile = KFile(libraryFile.absolutePath), - strategy = ToolingSingleFileKlibResolveStrategy - ) - if (kLibService.isAnalysisCompatible(kotlinLibrary)) { - // exists, is KLIB, has compatible format - put( - libraryFile.absolutePath, - kotlinLibrary - ) - } - } catch (e: Throwable) { - configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - .report(CompilerMessageSeverity.WARNING, "Can not resolve KLIB. " + e.message) - } - } - } - } - - private fun createCommonResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>, - environment: KotlinCoreEnvironment, - dependencyContainer: CommonDependenciesContainer? - ): ResolverForProject<ModuleInfo> { - return object : AbstractResolverForProject<ModuleInfo>( - "Dokka", - projectContext, - modules = module.dependencies() - ) { - override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module) - - override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance - - override fun createResolverForModule( - descriptor: ModuleDescriptor, - moduleInfo: ModuleInfo - ): ResolverForModule = - CommonResolverForModuleFactory( - CommonAnalysisParameters( - metadataPartProviderFactory = { content -> - environment.createPackagePartProvider(content.moduleContentScope) - } - ), - CompilerEnvironment, - unspecifiedJvmPlatform, - true, - dependencyContainer - ).createResolverForModule( - moduleDescriptor = descriptor as ModuleDescriptorImpl, - moduleContext = projectContext.withModule(descriptor), - moduleContent = modulesContent(moduleInfo), - resolverForProject = this, - languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, - sealedInheritorsProvider = CliSealedClassInheritorsProvider, - resolveOptimizingOptions = null, - absentDescriptorHandlerClass = null - ) - - override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null - } - } - - private fun createJsResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo> - ): ResolverForProject<ModuleInfo> { - return object : AbstractResolverForProject<ModuleInfo>( - "Dokka", - projectContext, - modules = module.dependencies() - ) { - override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module) - override fun createResolverForModule( - descriptor: ModuleDescriptor, - moduleInfo: ModuleInfo - ): ResolverForModule = DokkaJsResolverForModuleFactory(CompilerEnvironment, kLibService).createResolverForModule( - moduleDescriptor = descriptor as ModuleDescriptorImpl, - moduleContext = projectContext.withModule(descriptor), - moduleContent = modulesContent(moduleInfo), - resolverForProject = this, - languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, - sealedInheritorsProvider = CliSealedClassInheritorsProvider, - resolveOptimizingOptions = null, - absentDescriptorHandlerClass = null - ) - - override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance - - override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null - } - } - - private fun createNativeResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo> - ): ResolverForProject<ModuleInfo> { - return object : AbstractResolverForProject<ModuleInfo>( - "Dokka", - projectContext, - modules = module.dependencies() - ) { - override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = modulesContent(module) - override fun createResolverForModule( - descriptor: ModuleDescriptor, - moduleInfo: ModuleInfo - ): ResolverForModule { - - return DokkaNativeResolverForModuleFactory(CompilerEnvironment, kLibService).createResolverForModule( - moduleDescriptor = descriptor as ModuleDescriptorImpl, - moduleContext = projectContext.withModule(descriptor), - moduleContent = modulesContent(moduleInfo), - resolverForProject = this, - languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, - sealedInheritorsProvider = CliSealedClassInheritorsProvider, - resolveOptimizingOptions = null, - absentDescriptorHandlerClass = null - ) - } - - override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = DefaultBuiltIns.Instance - - override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null - } - } - - private fun createJvmResolverForProject( - projectContext: ProjectContext, - module: ModuleInfo, - library: LibraryModuleInfo, - modulesContent: (ModuleInfo) -> ModuleContent<ModuleInfo>, - sourcesScope: GlobalSearchScope, - builtIns: KotlinBuiltIns - ): ResolverForProject<ModuleInfo> { - val javaRoots = classpath - .mapNotNull { file -> - val rootFile = when (file.extension) { - "jar" -> StandardFileSystems.jar().findFileByPath("${file.absolutePath}$JAR_SEPARATOR") - else -> StandardFileSystems.local().findFileByPath(file.absolutePath) - } - rootFile?.let { JavaRoot(it, JavaRoot.RootType.BINARY) } - } - - return object : AbstractResolverForProject<ModuleInfo>( - "Dokka", - projectContext, - modules = listOf(module, library) - ) { - override fun modulesContent(module: ModuleInfo): ModuleContent<ModuleInfo> = - when (module) { - library -> ModuleContent(module, emptyList(), GlobalSearchScope.notScope(sourcesScope)) - module -> ModuleContent(module, emptyList(), sourcesScope) - else -> throw IllegalArgumentException("Unexpected module info") - } - - override fun builtInsForModule(module: ModuleInfo): KotlinBuiltIns = builtIns - - override fun createResolverForModule( - descriptor: ModuleDescriptor, - moduleInfo: ModuleInfo - ): ResolverForModule = JvmResolverForModuleFactory( - JvmPlatformParameters(packagePartProviderFactory = { content -> - JvmPackagePartProvider( - configuration.languageVersionSettings, - content.moduleContentScope - ) - .apply { - addRoots(javaRoots, messageCollector) - } - }, moduleByJavaClass = { - val file = - (it as? BinaryJavaClass)?.virtualFile ?: (it as JavaClassImpl).psi.containingFile.virtualFile - if (file in sourcesScope) - module - else - library - }, resolverForReferencedModule = null, - useBuiltinsProviderForModule = { false }), - CompilerEnvironment, - unspecifiedJvmPlatform - ).createResolverForModule( - moduleDescriptor = descriptor as ModuleDescriptorImpl, - moduleContext = projectContext.withModule(descriptor), - moduleContent = modulesContent(moduleInfo), - resolverForProject = this, - languageVersionSettings = configuration.languageVersionSettings, - sealedInheritorsProvider = CliSealedClassInheritorsProvider, - resolveOptimizingOptions = null, - absentDescriptorHandlerClass = null - ) - - override fun sdkDependency(module: ModuleInfo): ModuleInfo? = null - } - } - - 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) - configuration.languageVersionSettings = LanguageVersionSettingsImpl( - languageVersion = languageVersion, - apiVersion = apiVersion, analysisFlags = hashMapOf( - // force to resolve light classes (lazily by default) - AnalysisFlags.eagerResolveOfLightClasses to true - ) - ) - } - - /** - * Classpath for this environment. - */ - private val classpath: List<File> - get() = configuration.jvmClasspathRoots + configuration.getList(JSConfigurationKeys.LIBRARIES) - .mapNotNull { File(it) } - - /** - * Adds list of paths to classpath. - * $paths: collection of files to add - */ - internal fun addClasspath(paths: List<File>) { - if (analysisPlatform == Platform.js || analysisPlatform == Platform.wasm) { - configuration.addAll(JSConfigurationKeys.LIBRARIES, paths.map { it.absolutePath }) - } else { - configuration.addJvmClasspathRoots(paths) - } - } - - // Set up JDK classpath roots explicitly because of https://github.com/JetBrains/kotlin/commit/f89765eb33dd95c8de33a919cca83651b326b246 - internal fun configureJdkClasspathRoots() { - val jdkHome = File(System.getProperty("java.home")) - if (!jdkHome.exists()) { - messageCollector.report(CompilerMessageSeverity.WARNING, "Set existed java.home to use JDK") - } - configuration.put(JVMConfigurationKeys.JDK_HOME, jdkHome) - configuration.configureJdkClasspathRoots() // only non-nodular JDK - } - /** - * Adds path to classpath. - * $path: path to add - */ - internal fun addClasspath(path: File) { - if (analysisPlatform == Platform.js || analysisPlatform == Platform.wasm) { - configuration.add(JSConfigurationKeys.LIBRARIES, path.absolutePath) - } else { - configuration.addJvmClasspathRoot(path) - } - } - - /** - * List of source roots for this environment. - */ - internal val sources: List<String> - get() = configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) - ?.filterIsInstance<KotlinSourceRoot>() - ?.map { it.path } ?: emptyList() - - /** - * Adds list of paths to source roots. - * $list: collection of files to add - */ - internal fun addSources(sourceDirectories: Iterable<File>) { - sourceDirectories.forEach { directory -> - configuration.addKotlinSourceRoot(directory.path) - if (directory.isDirectory || directory.extension == "java") { - configuration.addJavaSourceRoot(directory) - } - } - } - - internal fun addRoots(list: List<ContentRoot>) { - configuration.addAll(CLIConfigurationKeys.CONTENT_ROOTS, list) - } - - /** - * Disposes the environment and frees all associated resources. - */ - override fun dispose() { - Disposer.dispose(this) - } - -} - - diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt deleted file mode 100644 index 068b4730..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/CallableFactory.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -import com.intellij.psi.PsiField -import com.intellij.psi.PsiMethod -import org.jetbrains.dokka.links.Callable -import org.jetbrains.dokka.links.JavaClassReference -import org.jetbrains.dokka.links.TypeReference -import org.jetbrains.kotlin.descriptors.CallableDescriptor - -internal fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null) = with(descriptor) { - Callable( - name ?: descriptor.name.asString(), - extensionReceiverParameter?.let { TypeReference.from(it) }, - valueParameters.mapNotNull { TypeReference.from(it) } - ) -} - -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() - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt deleted file mode 100644 index e2deaa8c..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRIFactory.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -import com.intellij.psi.* -import org.jetbrains.dokka.links.* -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 - -internal fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run { - val parameter = firstIsInstanceOrNull<ValueParameterDescriptor>() - val callable = parameter?.containingDeclaration ?: firstIsInstanceOrNull<CallableDescriptor>() - - DRI( - packageName = firstIsInstanceOrNull<PackageFragmentDescriptor>()?.fqName?.asString() ?: "", - classNames = (filterIsInstance<ClassDescriptor>() + filterIsInstance<TypeAliasDescriptor>()).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 as? ClassDescriptor)?.kind == ClassKind.ENUM_ENTRY) - DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode() - else null - ) -} - -internal fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run { - val psiMethod = firstIsInstanceOrNull<PsiMethod>() - val psiField = firstIsInstanceOrNull<PsiField>() - val classes = filterIsInstance<PsiClass>().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 - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt deleted file mode 100644 index f9d01ceb..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/DRITargetFactory.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiMethod -import com.intellij.psi.PsiParameter -import com.intellij.psi.PsiTypeParameter -import org.jetbrains.dokka.links.DriTarget -import org.jetbrains.dokka.links.PointingToCallableParameters -import org.jetbrains.dokka.links.PointingToDeclaration -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 - -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<CallableDescriptor>() - val params = - callable?.let { listOfNotNull(it.extensionReceiverParameter) + it.valueParameters }.orEmpty() - val parameterDescriptor = firstIsInstanceOrNull<ParameterDescriptor>() - - parameterDescriptor?.let { PointingToCallableParameters(params.indexOf(it)) } - ?: PointingToDeclaration - } - } -} - - -internal fun DriTarget.Companion.from(psi: PsiElement): DriTarget = psi.parentsWithSelf.run { - return when (psi) { - is PsiTypeParameter -> PointingToGenericParameters(psi.index) - else -> firstIsInstanceOrNull<PsiParameter>()?.let { - val callable = firstIsInstanceOrNull<PsiMethod>() - val params = (callable?.parameterList?.parameters).orEmpty() - PointingToCallableParameters(params.indexOf(it)) - } ?: PointingToDeclaration - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt deleted file mode 100644 index ad5eb048..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/Documentable.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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 fun computeLineNumber(): Int? { - return (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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt deleted file mode 100644 index da18a952..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/JvmDependenciesIndexImpl.kt +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -/** - * DO NOT MOVE IT - * This is a hack for https://github.com/Kotlin/dokka/issues/1599 - * - * Copy-pasted from 1.9.20-Beta-1 - * Can be removed for Kotlin compiler 1.9.20 and later - * - * It makes this class threadsafe for Dokka - */ -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.cli.jvm.index - -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 gnu.trove.THashMap -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import java.util.* -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock - -// speeds up finding files/classes in classpath/java source roots -// TODO: KT-58327 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 -public class JvmDependenciesIndexImpl(_roots: List<JavaRoot>) : JvmDependenciesIndex { - private val lock = ReentrantLock() - - //these fields are computed based on _roots passed to constructor which are filled in later - private val roots: List<JavaRoot> by lazy { _roots.toList() } - - private val maxIndex: Int - get() = roots.size - - // each "Cache" object corresponds to a package - private class Cache { - private val innerPackageCaches = HashMap<String, Cache>() - - operator fun get(name: String) = innerPackageCaches.getOrPut(name, ::Cache) - - // indices of roots that are known to contain this package - // if this list contains [1, 3, 5] then roots with indices 1, 3 and 5 are known to contain this package, 2 and 4 are known not to (no information about roots 6 or higher) - // if this list contains maxIndex that means that all roots containing this package are known - @Suppress("DEPRECATION") // TODO: fix deprecation - val rootIndices = com.intellij.util.containers.IntArrayList(2) - } - - // root "Cache" object corresponds to DefaultPackage which exists in every root. Roots with non-default fqname are also listed here but - // they will be ignored on requests with invalid fqname prefix. - private val rootCache: Cache by lazy { - Cache().apply { - roots.indices.forEach(rootIndices::add) - rootIndices.add(maxIndex) - rootIndices.trimToSize() - } - } - - // holds the request and the result last time we searched for class - // helps improve several scenarios, LazyJavaResolverContext.findClassInJava being the most important - private var lastClassSearch: Pair<FindClassRequest, SearchResult>? = null - - override val indexedRoots: Sequence<JavaRoot> by lazy { roots.asSequence() } - - private val packageCache: Array<out MutableMap<String, VirtualFile?>> by lazy { - Array(roots.size) { THashMap<String, VirtualFile?>() } - } - - override fun traverseDirectoriesInPackage( - packageFqName: FqName, - acceptedRootTypes: Set<JavaRoot.RootType>, - continueSearch: (VirtualFile, JavaRoot.RootType) -> Boolean - ) { - lock.withLock { - search(TraverseRequest(packageFqName, acceptedRootTypes)) { dir, rootType -> - if (continueSearch(dir, rootType)) null else Unit - } - } - } - - // findClassGivenDirectory MUST check whether the class with this classId exists in given package - override fun <T : Any> findClass( - classId: ClassId, - acceptedRootTypes: Set<JavaRoot.RootType>, - findClassGivenDirectory: (VirtualFile, JavaRoot.RootType) -> T? - ): T? { - lock.withLock { - // TODO: KT-58327 probably should be changed to thread local to fix fast-path - // make a decision based on information saved from last class search - if (lastClassSearch?.first?.classId != classId) { - return search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory) - } - - val (cachedRequest, cachedResult) = lastClassSearch!! - return when (cachedResult) { - is SearchResult.NotFound -> { - val limitedRootTypes = acceptedRootTypes - cachedRequest.acceptedRootTypes - if (limitedRootTypes.isEmpty()) { - null - } else { - search(FindClassRequest(classId, limitedRootTypes), findClassGivenDirectory) - } - } - is SearchResult.Found -> { - if (cachedRequest.acceptedRootTypes == acceptedRootTypes) { - findClassGivenDirectory(cachedResult.packageDirectory, cachedResult.root.type) - } else { - search(FindClassRequest(classId, acceptedRootTypes), findClassGivenDirectory) - } - } - } - } - } - - private fun <T : Any> search(request: SearchRequest, handler: (VirtualFile, JavaRoot.RootType) -> T?): T? { - // a list of package sub names, ["org", "jb", "kotlin"] - val packagesPath = request.packageFqName.pathSegments().map { it.identifierOrNullIfSpecial ?: return null } - // a list of caches corresponding to packages, [default, "org", "org.jb", "org.jb.kotlin"] - val caches = cachesPath(packagesPath) - - var processedRootsUpTo = -1 - // traverse caches starting from last, which contains most specific information - - // NOTE: indices manipulation instead of using caches.reversed() is here for performance reasons - for (cacheIndex in caches.lastIndex downTo 0) { - val cacheRootIndices = caches[cacheIndex].rootIndices - for (i in 0 until cacheRootIndices.size()) { - val rootIndex = cacheRootIndices[i] - if (rootIndex <= processedRootsUpTo) continue // roots with those indices have been processed by now - - val directoryInRoot = travelPath(rootIndex, request.packageFqName, packagesPath, cacheIndex, caches) ?: continue - val root = roots[rootIndex] - if (root.type in request.acceptedRootTypes) { - val result = handler(directoryInRoot, root.type) - if (result != null) { - if (request is FindClassRequest) { - lastClassSearch = Pair(request, SearchResult.Found(directoryInRoot, root)) - } - return result - } - } - } - processedRootsUpTo = if (cacheRootIndices.isEmpty) processedRootsUpTo else cacheRootIndices[cacheRootIndices.size() - 1] - } - - if (request is FindClassRequest) { - lastClassSearch = Pair(request, SearchResult.NotFound) - } - return null - } - - // try to find a target directory corresponding to package represented by packagesPath in a given root represented by index - // possibly filling "Cache" objects with new information - private fun travelPath( - rootIndex: Int, - packageFqName: FqName, - packagesPath: List<String>, - fillCachesAfter: Int, - cachesPath: List<Cache> - ): VirtualFile? { - if (rootIndex >= maxIndex) { - 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.trimToSize() - } - return null - } - - return packageCache[rootIndex].getOrPut(packageFqName.asString()) { - doTravelPath(rootIndex, packagesPath, fillCachesAfter, cachesPath) - } - } - - private fun doTravelPath(rootIndex: Int, packagesPath: List<String>, fillCachesAfter: Int, cachesPath: List<Cache>): VirtualFile? { - val pathRoot = roots[rootIndex] - val prefixPathSegments = pathRoot.prefixFqName?.pathSegments() - - var currentFile = pathRoot.file - - for (pathIndex in packagesPath.indices) { - val subPackageName = packagesPath[pathIndex] - if (prefixPathSegments != null && pathIndex < prefixPathSegments.size) { - // Traverse prefix first instead of traversing real directories - if (prefixPathSegments[pathIndex].identifier != subPackageName) { - return null - } - } else { - currentFile = currentFile.findChildPackage(subPackageName, pathRoot.type) ?: return null - } - - val correspondingCacheIndex = pathIndex + 1 - if (correspondingCacheIndex > fillCachesAfter) { - // subPackageName exists in this root - cachesPath[correspondingCacheIndex].rootIndices.add(rootIndex) - } - } - - return currentFile - } - - private fun VirtualFile.findChildPackage(subPackageName: String, rootType: JavaRoot.RootType): VirtualFile? { - val childDirectory = findChild(subPackageName) ?: return null - - val fileExtension = when (rootType) { - JavaRoot.RootType.BINARY -> JavaClassFileType.INSTANCE.defaultExtension - JavaRoot.RootType.BINARY_SIG -> "sig" - JavaRoot.RootType.SOURCE -> JavaFileType.INSTANCE.defaultExtension - } - - // If in addition to a directory "foo" there's a class file "foo.class" AND there are no classes anywhere in the directory "foo", - // then we ignore the directory and let the resolution choose the class "foo" instead. - if (findChild("$subPackageName.$fileExtension")?.isDirectory == false) { - if (VfsUtilCore.processFilesRecursively(childDirectory) { file -> file.extension != fileExtension }) { - return null - } - } - - return childDirectory - } - - private fun cachesPath(path: List<String>): List<Cache> { - val caches = ArrayList<Cache>(path.size + 1) - caches.add(rootCache) - var currentCache = rootCache - for (subPackageName in path) { - currentCache = currentCache[subPackageName] - caches.add(currentCache) - } - return caches - } - - private data class FindClassRequest(val classId: ClassId, override val acceptedRootTypes: Set<JavaRoot.RootType>) : SearchRequest { - override val packageFqName: FqName - get() = classId.packageFqName - } - - private data class TraverseRequest( - override val packageFqName: FqName, - override val acceptedRootTypes: Set<JavaRoot.RootType> - ) : SearchRequest - - private interface SearchRequest { - val packageFqName: FqName - val acceptedRootTypes: Set<JavaRoot.RootType> - } - - private sealed class SearchResult { - class Found(val packageDirectory: VirtualFile, val root: JavaRoot) : SearchResult() - - object NotFound : SearchResult() - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt deleted file mode 100644 index 4e6f42c9..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinAnalysis.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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.ConfigurableBlock -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import java.io.Closeable - -@OptIn(DokkaPluginApiPreview::class) -@Suppress("FunctionName") -internal fun ProjectKotlinAnalysis( - sourceSets: List<DokkaSourceSet>, - context: DokkaContext, - analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration() -): KotlinAnalysis { - val environments = sourceSets.associateWith { sourceSet -> - createAnalysisContext( - context = context, - sourceSets = sourceSets, - sourceSet = sourceSet, - analysisConfiguration = analysisConfiguration - ) - } - return EnvironmentKotlinAnalysis(environments) -} - -/** - * [projectKotlinAnalysis] needs to be closed separately - * Usually the analysis created for samples is short-lived and can be closed right after - * it's been used, there's no need to wait for [projectKotlinAnalysis] to be closed as it must be handled separately. - */ -@OptIn(DokkaPluginApiPreview::class) -@Suppress("FunctionName") -internal fun SamplesKotlinAnalysis( - sourceSets: List<DokkaSourceSet>, - context: DokkaContext, - projectKotlinAnalysis: KotlinAnalysis, - analysisConfiguration: DokkaAnalysisConfiguration = DokkaAnalysisConfiguration() -): KotlinAnalysis { - val environments = sourceSets - .filter { it.samples.isNotEmpty() } - .associateWith { sourceSet -> - createAnalysisContext( - context = context, - classpath = sourceSet.classpath, - sourceRoots = sourceSet.samples, - sourceSet = sourceSet, - analysisConfiguration = analysisConfiguration - ) - } - - return EnvironmentKotlinAnalysis(environments, projectKotlinAnalysis) -} -@DokkaPluginApiPreview -public data 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. - */ - val ignoreCommonBuiltIns: Boolean = DEFAULT_IGNORE_COMMON_BUILT_INS -): ConfigurableBlock { - public companion object { - public const val DEFAULT_IGNORE_COMMON_BUILT_INS: Boolean = false - } -} - -/** - * First child delegation. It does not close [parent]. - */ -@InternalDokkaApi -public abstract class KotlinAnalysis( - private val parent: KotlinAnalysis? = null -) : Closeable { - - public operator fun get(key: DokkaSourceSet): AnalysisContext { - return get(key.sourceSetID) - } - - internal operator fun get(key: DokkaSourceSetID): AnalysisContext { - return find(key) - ?: parent?.get(key) - ?: throw IllegalStateException("Missing EnvironmentAndFacade for sourceSet $key") - } - - internal abstract fun find(sourceSetID: DokkaSourceSetID): AnalysisContext? -} - -internal open class EnvironmentKotlinAnalysis( - private val environments: SourceSetDependent<AnalysisContext>, - parent: KotlinAnalysis? = null, -) : KotlinAnalysis(parent = parent) { - - override fun find(sourceSetID: DokkaSourceSetID): AnalysisContext? = - environments.entries.firstOrNull { (sourceSet, _) -> sourceSet.sourceSetID == sourceSetID }?.value - - override fun close() { - environments.values.forEach(AnalysisContext::close) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt deleted file mode 100644 index 3d340672..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/KotlinCliJavaFileManagerImpl.kt +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -/** - * DO NOT MOVE IT - * This is a hack for https://github.com/Kotlin/dokka/issues/1599 - * - * Copy-pasted from Kotlin compiler - * - * It makes this class threadsafe (`topLevelClassesCache` and `binaryCache`) for Dokka - * - */ -@file:Suppress("PackageDirectoryMismatch") -package org.jetbrains.kotlin.cli.jvm.compiler - -import com.intellij.core.CoreJavaFileManager -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.* -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.index.JavaRoot -import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex -import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex -import org.jetbrains.kotlin.load.java.JavaClassFinder -import org.jetbrains.kotlin.load.java.structure.JavaClass -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext -import org.jetbrains.kotlin.load.java.structure.impl.classFiles.isNotTopLevelClass -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 - -// 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 -public 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 - private lateinit var packagePartProviders: List<JvmPackagePartProvider> - private val topLevelClassesCache: MutableMap<FqName, VirtualFile?> = THashMap() - private val allScope = GlobalSearchScope.allScope(myPsiManager.project) - private var usePsiClassFilesReading = false - - public fun initialize( - index: JvmDependenciesIndex, - packagePartProviders: List<JvmPackagePartProvider>, - singleJavaFileRootsIndex: SingleJavaFileRootsIndex, - usePsiClassFilesReading: Boolean - ) { - this.index = index - this.packagePartProviders = packagePartProviders - this.singleJavaFileRootsIndex = singleJavaFileRootsIndex - this.usePsiClassFilesReading = usePsiClassFilesReading - } - - private fun findPsiClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? = perfCounter.time { - findVirtualFileForTopLevelClass(classId, searchScope)?.findPsiClassInVirtualFile(classId.relativeClassName.asString()) - } - - private fun findVirtualFileForTopLevelClass(classId: ClassId, searchScope: GlobalSearchScope): VirtualFile? { - val relativeClassName = classId.relativeClassName.asString() - synchronized(topLevelClassesCache) { - return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) { - index.findClass(classId) { dir, type -> - findVirtualFileGivenPackage(dir, relativeClassName, type) - } ?: singleJavaFileRootsIndex.findJavaSourceClass(classId) - }?.takeIf { it in searchScope } - } - } - - private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap() - private val signatureParsingComponent = BinaryClassSignatureParser() - - public fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope) - - override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? { - val (classId, classFileContentFromRequest, outerClassFromRequest) = request - val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null - - if (!usePsiClassFilesReading && (virtualFile.extension == "class" || virtualFile.extension == "sig")) { - synchronized(binaryCache){ - // We return all class files' names in the directory in knownClassNamesInPackage method, so one may request an inner class - return binaryCache.getOrPut(classId) { - // Note that currently we implicitly suppose that searchScope for binary classes is constant and we do not use it - // as a key in cache - // This is a true assumption by now since there are two search scopes in compiler: one for sources and another one for binary - // When it become wrong because we introduce the modules into CLI, it's worth to consider - // having different KotlinCliJavaFileManagerImpl's for different modules - - classId.outerClassId?.let { outerClassId -> - val outerClass = outerClassFromRequest ?: findClass(outerClassId, searchScope) - - return if (outerClass is BinaryJavaClass) - outerClass.findInnerClass(classId.shortClassName, classFileContentFromRequest) - else - outerClass?.findInnerClass(classId.shortClassName) - } - - // Here, we assume the class is top-level - val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray() - if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null - - val resolver = ClassifierResolutionContext { findClass(it, allScope) } - - BinaryJavaClass( - virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent, - outerClass = null, classContent = classContent - ) - } - } - } - - return virtualFile.findPsiClassInVirtualFile(classId.relativeClassName.asString())?.let(::JavaClassImpl) - } - - // this method is called from IDEA to resolve dependencies in Java code - // which supposedly shouldn't have errors so the dependencies exist in general - override fun findClass(qName: String, scope: GlobalSearchScope): PsiClass? { - // String cannot be reliably converted to ClassId because we don't know where the package name ends and class names begin. - // For example, if qName is "a.b.c.d.e", we should either look for a top level class "e" in the package "a.b.c.d", - // or, for example, for a nested class with the relative qualified name "c.d.e" in the package "a.b". - // Below, we start by looking for the top level class "e" in the package "a.b.c.d" first, then for the class "d.e" in the package - // "a.b.c", and so on, until we find something. Most classes are top level, so most of the times the search ends quickly - - forEachClassId(qName) { classId -> - findPsiClass(classId, scope)?.let { return it } - } - - return null - } - - private inline fun forEachClassId(fqName: String, block: (ClassId) -> Unit) { - var classId = fqName.toSafeTopLevelClassId() ?: return - - while (true) { - block(classId) - - val packageFqName = classId.packageFqName - if (packageFqName.isRoot) break - - classId = ClassId( - packageFqName.parent(), - FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), - false - ) - } - } - - override fun findClasses(qName: String, scope: GlobalSearchScope): Array<PsiClass> = perfCounter.time { - val result = ArrayList<PsiClass>(1) - forEachClassId(qName) { classId -> - val relativeClassName = classId.relativeClassName.asString() - index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> - val psiClass = - findVirtualFileGivenPackage(dir, relativeClassName, rootType) - ?.takeIf { it in scope } - ?.findPsiClassInVirtualFile(relativeClassName) - if (psiClass != null) { - result.add(psiClass) - } - // traverse all - true - } - - singleJavaFileRootsIndex.findJavaSourceClass(classId) - ?.takeIf { it in scope } - ?.findPsiClassInVirtualFile(relativeClassName) - ?.let { result.add(it) } - - if (result.isNotEmpty()) { - return@time result.toTypedArray() - } - } - - PsiClass.EMPTY_ARRAY - } - - override fun findPackage(packageName: String): PsiPackage? { - var found = false - val packageFqName = packageName.toSafeFqName() ?: return null - index.traverseDirectoriesInPackage(packageFqName) { _, _ -> - found = true - //abort on first found - false - } - if (!found) { - found = packagePartProviders.any { it.findPackageParts(packageName).isNotEmpty() } - } - if (!found) { - found = singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName).isNotEmpty() - } - return if (found) PsiPackageImpl(myPsiManager, packageName) else null - } - - private fun findVirtualFileGivenPackage( - packageDir: VirtualFile, - classNameWithInnerClasses: String, - rootType: JavaRoot.RootType - ): VirtualFile? { - val topLevelClassName = classNameWithInnerClasses.substringBefore('.') - - val vFile = when (rootType) { - JavaRoot.RootType.BINARY -> packageDir.findChild("$topLevelClassName.class") - JavaRoot.RootType.BINARY_SIG -> packageDir.findChild("$topLevelClassName.sig") - JavaRoot.RootType.SOURCE -> packageDir.findChild("$topLevelClassName.java") - } ?: return null - - if (!vFile.isValid) { - LOG.error("Invalid child of valid parent: ${vFile.path}; ${packageDir.isValid} path=${packageDir.path}") - return null - } - - return vFile - } - - private fun VirtualFile.findPsiClassInVirtualFile(classNameWithInnerClasses: String): PsiClass? { - val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null - return findClassInPsiFile(classNameWithInnerClasses, file) - } - - override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> { - val result = THashSet<String>() - index.traverseDirectoriesInPackage(packageFqName, continueSearch = { dir, _ -> - for (child in dir.children) { - if (child.extension == "class" || child.extension == "java" || child.extension == "sig") { - result.add(child.nameWithoutExtension) - } - } - - true - }) - - for (classId in singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName)) { - assert(!classId.isNestedClass) { "ClassId of a single .java source class should not be nested: $classId" } - result.add(classId.shortClassName.asString()) - } - - return result - } - - override fun findModules(moduleName: String, scope: GlobalSearchScope): Collection<PsiJavaModule> { - // TODO - return emptySet() - } - - override fun getNonTrivialPackagePrefixes(): Collection<String> = emptyList() - - public companion object { - private val LOG = Logger.getInstance(KotlinCliJavaFileManagerImpl::class.java) - - private fun findClassInPsiFile(classNameWithInnerClassesDotSeparated: String, file: PsiClassOwner): PsiClass? { - for (topLevelClass in file.classes) { - val candidate = findClassByTopLevelClass(classNameWithInnerClassesDotSeparated, topLevelClass) - if (candidate != null) { - return candidate - } - } - return null - } - - private fun findClassByTopLevelClass(className: String, topLevelClass: PsiClass): PsiClass? { - if (className.indexOf('.') < 0) { - return if (className == topLevelClass.name) topLevelClass else null - } - - val segments = StringUtil.split(className, ".").iterator() - if (!segments.hasNext() || segments.next() != topLevelClass.name) { - return null - } - var curClass = topLevelClass - while (segments.hasNext()) { - val innerClassName = segments.next() - val innerClass = curClass.findInnerClassByName(innerClassName, false) ?: return null - curClass = innerClass - } - return curClass - } - } -} - -// a sad workaround to avoid throwing exception when called from inside IDEA code -private fun <T : Any> safely(compute: () -> T): T? = - try { - compute() - } catch (e: IllegalArgumentException) { - null - } catch (e: AssertionError) { - null - } - -private fun String.toSafeFqName(): FqName? = safely { FqName(this) } -private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) } diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt deleted file mode 100644 index b6929cbb..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration - -import com.intellij.psi.PsiClass -import org.jetbrains.dokka.links.* -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjection -import org.jetbrains.kotlin.types.error.ErrorType -import org.jetbrains.kotlin.types.error.ErrorTypeConstructor -import org.jetbrains.kotlin.types.error.ErrorTypeKind - -internal fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference? = - when (d.value) { - is ExtensionReceiver -> fromPossiblyNullable(d.type, emptyList()) - else -> run { - println("Unknown value type for $d") - null - } - } - -internal fun TypeReference.Companion.from(d: ValueParameterDescriptor): TypeReference = - fromPossiblyNullable(d.type, emptyList()) - -internal fun TypeReference.Companion.from(@Suppress("UNUSED_PARAMETER") p: PsiClass) = TypeReference - -private fun TypeReference.Companion.fromPossiblyNullable(t: KotlinType, paramTrace: List<KotlinType>): TypeReference = - fromPossiblyRecursive(t, paramTrace).let { if (t.isMarkedNullable) Nullable(it) else it } - -private fun TypeReference.Companion.fromPossiblyRecursive(t: KotlinType, paramTrace: List<KotlinType>): TypeReference = - paramTrace.indexOfFirst { it.constructor == t.constructor && it.arguments == t.arguments } - .takeIf { it >= 0 } - ?.let(::RecursiveType) - ?: from(t, paramTrace) - -private fun TypeReference.Companion.from(t: KotlinType, paramTrace: List<KotlinType>): TypeReference { - if (t is ErrorType) { - val errorConstructor = t.constructor as? ErrorTypeConstructor - val presentableName = - if (errorConstructor?.kind == ErrorTypeKind.UNRESOLVED_TYPE && errorConstructor.parameters.isNotEmpty()) - errorConstructor.getParam(0) - else - t.constructor.toString() - return TypeConstructor(presentableName, t.arguments.map { fromProjection(it, paramTrace) }) - } - return when (val d = t.constructor.declarationDescriptor) { - is TypeParameterDescriptor -> TypeParam( - d.upperBounds.map { fromPossiblyNullable(it, paramTrace + t) } - ) - else -> TypeConstructor( - t.constructorName.orEmpty(), - t.arguments.map { fromProjection(it, paramTrace) } - ) - } -} - -private fun TypeReference.Companion.fromProjection(t: TypeProjection, paramTrace: List<KotlinType>): TypeReference = - if (t.isStarProjection) { - StarProjection - } else { - fromPossiblyNullable(t.type, paramTrace) - } - -private val KotlinType.constructorName - get() = constructor.declarationDescriptor?.fqNameSafe?.asString() diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt deleted file mode 100644 index 9f5ecc40..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/CommonKlibModuleInfo.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.CommonPlatforms -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices - -internal class CommonKlibModuleInfo( - override val name: Name, - val kotlinLibrary: KotlinLibrary, - private val dependOnModules: List<ModuleInfo> -) : ModuleInfo { - override fun dependencies(): List<ModuleInfo> = dependOnModules - - override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns = ModuleInfo.DependencyOnBuiltIns.LAST - - override val platform: TargetPlatform - get() = CommonPlatforms.defaultCommonPlatform - - override val analyzerServices: PlatformDependentAnalyzerServices - get() = CommonPlatformAnalyzerServices -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt deleted file mode 100644 index 480bc7cb..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsKlibLibraryInfo.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.shortName -import org.jetbrains.kotlin.library.uniqueName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.platform.js.JsPlatforms -import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices - -/** TODO: replace by [org.jetbrains.kotlin.caches.resolve.JsKlibLibraryInfo] after fix of KT-40734 */ -internal class DokkaJsKlibLibraryInfo( - override val kotlinLibrary: KotlinLibrary, - override val analyzerServices: PlatformDependentAnalyzerServices, - private val dependencyResolver: DokkaKlibLibraryDependencyResolver -) : DokkaKlibLibraryInfo() { - init { - dependencyResolver.registerLibrary(this) - } - - override val name: Name by lazy { - val libraryName = kotlinLibrary.shortName ?: kotlinLibrary.uniqueName - Name.special("<$libraryName>") - } - - override val platform: TargetPlatform = JsPlatforms.defaultJsPlatform - override fun dependencies(): List<ModuleInfo> = listOf(this) + dependencyResolver.resolveDependencies(this) - override fun getLibraryRoots(): Collection<String> = listOf(libraryRoot) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt deleted file mode 100644 index 98f9c64a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaJsResolverForModuleFactory.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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 -import org.jetbrains.kotlin.container.StorageComponentContainer -import org.jetbrains.kotlin.container.get -import org.jetbrains.kotlin.context.ModuleContext -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.incremental.components.LookupTracker -import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices -import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories -import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer -import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider -import org.jetbrains.kotlin.resolve.TargetEnvironment -import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService -import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer -import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil -import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider -import org.jetbrains.kotlin.library.metadata.impl.KlibMetadataModuleDescriptorFactoryImpl -import org.jetbrains.kotlin.resolve.lazy.AbsentDescriptorHandler -import org.jetbrains.kotlin.resolve.scopes.optimization.OptimizingOptions -import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils -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 kLibService: KLibService -) : ResolverForModuleFactory() { - companion object { - private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, DynamicTypeDeserializer) - - private val metadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl( - metadataFactories.DefaultDescriptorFactory, - metadataFactories.DefaultPackageFragmentsFactory, - metadataFactories.flexibleTypeDeserializer, - ) - } - - override fun <M : ModuleInfo> createResolverForModule( - moduleDescriptor: ModuleDescriptorImpl, - moduleContext: ModuleContext, - moduleContent: ModuleContent<M>, - resolverForProject: ResolverForProject<M>, - languageVersionSettings: LanguageVersionSettings, - sealedInheritorsProvider: SealedClassInheritorsProvider, - resolveOptimizingOptions: OptimizingOptions?, - absentDescriptorHandlerClass: Class<out AbsentDescriptorHandler>? - ): ResolverForModule { - val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( - moduleContext.project, - moduleContext.storageManager, - moduleContent.syntheticFiles, - moduleContent.moduleContentScope, - moduleContent.moduleInfo - ) - - val container = createContainerForLazyResolve( - moduleContext = moduleContext, - declarationProviderFactory = declarationProviderFactory, - bindingTrace = CodeAnalyzerInitializer.getInstance(moduleContext.project).createTrace(), // BindingTraceContext(/* allowSliceRewrite = */ true), - platform = moduleDescriptor.platform!!, - analyzerServices = JsPlatformAnalyzerServices, - targetEnvironment = targetEnvironment, - languageVersionSettings = languageVersionSettings, - absentDescriptorHandlerClass = absentDescriptorHandlerClass - ) - - var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider - - val libraryProviders = createPackageFragmentProvider(moduleContent.moduleInfo, container, moduleContext, moduleDescriptor, languageVersionSettings) - - if (libraryProviders.isNotEmpty()) { - packageFragmentProvider = - CompositePackageFragmentProvider(listOf(packageFragmentProvider) + libraryProviders, "DokkaCompositePackageFragmentProvider") - } - return ResolverForModule(packageFragmentProvider, container) - } - - internal fun <M : ModuleInfo> createPackageFragmentProvider( - moduleInfo: M, - container: StorageComponentContainer, - moduleContext: ModuleContext, - moduleDescriptor: ModuleDescriptorImpl, - languageVersionSettings: LanguageVersionSettings - ): List<PackageFragmentProvider> = when (moduleInfo) { - is DokkaJsKlibLibraryInfo -> { - with(kLibService) { - listOfNotNull( - moduleInfo.kotlinLibrary - .createPackageFragmentProvider( - storageManager = moduleContext.storageManager, - metadataModuleDescriptorFactory = metadataModuleDescriptorFactory, - languageVersionSettings = languageVersionSettings, - moduleDescriptor = moduleDescriptor, - lookupTracker = LookupTracker.DO_NOTHING - ) - ) - } - } - is LibraryModuleInfo -> { - moduleInfo.getLibraryRoots() - .flatMap { - if (File(it).exists()) { - KotlinJavascriptMetadataUtils.loadMetadata(it) - } else { - // TODO can/should we warn a user about a problem in a library root? If so how? - emptyList() - } - } - .filter { it.version.isCompatibleWithCurrentCompilerVersion() } - .map { metadata -> - val (header, packageFragmentProtos) = - KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version) - createKotlinJavascriptPackageFragmentProvider( - moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version, - container.get(), LookupTracker.DO_NOTHING - ) - } - } - else -> emptyList() - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt deleted file mode 100644 index 8d275ad8..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryDependencyResolver.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.library.uniqueName -import org.jetbrains.kotlin.library.unresolvedDependencies - -/** TODO: replace by [NativeKlibLibraryInfo] after fix of KT-40734 */ -internal class DokkaKlibLibraryDependencyResolver { - private val cachedDependencies = mutableMapOf</* libraryName */String, DokkaKlibLibraryInfo>() - - fun registerLibrary(libraryInfo: DokkaKlibLibraryInfo) { - cachedDependencies[libraryInfo.kotlinLibrary.uniqueName] = libraryInfo - } - - fun resolveDependencies(libraryInfo: DokkaKlibLibraryInfo): List<DokkaKlibLibraryInfo> { - return libraryInfo.kotlinLibrary.unresolvedDependencies.mapNotNull { cachedDependencies[it.path] } - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt deleted file mode 100644 index 28a674af..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibLibraryInfo.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.analyzer.LibraryModuleInfo -import org.jetbrains.kotlin.library.KotlinLibrary - -internal abstract class DokkaKlibLibraryInfo : LibraryModuleInfo { - abstract val kotlinLibrary: KotlinLibrary - internal val libraryRoot: String - get() = kotlinLibrary.libraryFile.path -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt deleted file mode 100644 index 09f4e48a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaKlibMetadataCommonDependencyContainer.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer -import org.jetbrains.kotlin.builtins.DefaultBuiltIns -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.config.languageVersionSettings -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin -import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer -import org.jetbrains.kotlin.library.metadata.parseModuleHeader -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration -import org.jetbrains.kotlin.library.metadata.impl.KlibMetadataModuleDescriptorFactoryImpl -import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.storage.StorageManager - -/** - * Adapted from org.jetbrains.kotlin.cli.metadata.KlibMetadataDependencyContainer - */ -internal class DokkaKlibMetadataCommonDependencyContainer( - kotlinLibraries: List<KotlinLibrary>, - private val configuration: CompilerConfiguration, - private val storageManager: StorageManager -) : CommonDependenciesContainer { - - private val builtIns - get() = DefaultBuiltIns.Instance - - private val mutableDependenciesForAllModuleDescriptors = mutableListOf<ModuleDescriptorImpl>().apply { - add(builtIns.builtInsModule) - } - - private val mutableDependenciesForAllModules = mutableListOf<ModuleInfo>() - - private val moduleDescriptorsForKotlinLibraries: Map<KotlinLibrary, ModuleDescriptorImpl> = - kotlinLibraries.associateBy({ it }) { library -> - val moduleHeader = parseModuleHeader(library.moduleHeaderData) - val moduleName = Name.special(moduleHeader.moduleName) - val moduleOrigin = DeserializedKlibModuleOrigin(library) - MetadataFactories.DefaultDescriptorFactory.createDescriptor( - moduleName, storageManager, builtIns, moduleOrigin - ) - }.also { result -> - val resultValues = result.values - resultValues.forEach { module -> - module.setDependencies(mutableDependenciesForAllModuleDescriptors) - } - mutableDependenciesForAllModuleDescriptors.addAll(resultValues) - } - - private val moduleInfosImpl: List<CommonKlibModuleInfo> = mutableListOf<CommonKlibModuleInfo>().apply { - addAll( - moduleDescriptorsForKotlinLibraries.map { (kotlinLibrary, moduleDescriptor) -> - CommonKlibModuleInfo(moduleDescriptor.name, kotlinLibrary, mutableDependenciesForAllModules) - } - ) - mutableDependenciesForAllModules.addAll(this@apply) - } - - override val moduleInfos: List<ModuleInfo> get() = moduleInfosImpl - - /* not used in Dokka */ - override val friendModuleInfos: List<ModuleInfo> = emptyList() - - /* not used in Dokka */ - override val refinesModuleInfos: List<ModuleInfo> = emptyList() - - override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor { - if (moduleInfo !in moduleInfos) - error("Unknown module info $moduleInfo") - - // Ensure that the package fragment provider has been created and the module descriptor has been - // initialized with the package fragment provider: - packageFragmentProviderForModuleInfo(moduleInfo) - - return moduleDescriptorsForKotlinLibraries.getValue((moduleInfo as CommonKlibModuleInfo).kotlinLibrary) - } - - override fun registerDependencyForAllModules( - moduleInfo: ModuleInfo, - descriptorForModule: ModuleDescriptorImpl - ) { - mutableDependenciesForAllModules.add(moduleInfo) - mutableDependenciesForAllModuleDescriptors.add(descriptorForModule) - } - - override fun packageFragmentProviderForModuleInfo( - moduleInfo: ModuleInfo - ): PackageFragmentProvider? { - if (moduleInfo !in moduleInfos) - return null - return packageFragmentProviderForKotlinLibrary((moduleInfo as CommonKlibModuleInfo).kotlinLibrary) - } - - private val klibMetadataModuleDescriptorFactory by lazy { - KlibMetadataModuleDescriptorFactoryImpl( - MetadataFactories.DefaultDescriptorFactory, - MetadataFactories.DefaultPackageFragmentsFactory, - MetadataFactories.flexibleTypeDeserializer - ) - } - - private fun packageFragmentProviderForKotlinLibrary( - library: KotlinLibrary - ): PackageFragmentProvider { - val languageVersionSettings = configuration.languageVersionSettings - - val libraryModuleDescriptor = moduleDescriptorsForKotlinLibraries.getValue(library) - val packageFragmentNames = parseModuleHeader(library.moduleHeaderData).packageFragmentNameList - - return klibMetadataModuleDescriptorFactory.createPackageFragmentProvider( - library, - packageAccessHandler = null, - packageFragmentNames = packageFragmentNames, - storageManager = LockBasedStorageManager("KlibMetadataPackageFragmentProvider"), - moduleDescriptor = libraryModuleDescriptor, - configuration = CompilerDeserializationConfiguration(languageVersionSettings), - compositePackageFragmentAddend = null, - lookupTracker = LookupTracker.DO_NOTHING - ).also { - libraryModuleDescriptor.initialize(it) - } - } -} - -private val MetadataFactories = - KlibMetadataFactories( - { DefaultBuiltIns.Instance }, - NullFlexibleTypeDeserializer - ) diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt deleted file mode 100644 index 25cfb406..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeKlibLibraryInfo.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.resolve - -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.descriptors.ModuleCapability -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin -import org.jetbrains.kotlin.library.metadata.KlibModuleOrigin -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.isInterop -import org.jetbrains.kotlin.library.shortName -import org.jetbrains.kotlin.library.uniqueName -import org.jetbrains.kotlin.name.Name -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( - override val kotlinLibrary: KotlinLibrary, - override val analyzerServices: PlatformDependentAnalyzerServices, - private val dependencyResolver: DokkaKlibLibraryDependencyResolver -) : DokkaKlibLibraryInfo() { - init { - dependencyResolver.registerLibrary(this) - } - - override val name: Name by lazy { - val libraryName = kotlinLibrary.shortName ?: kotlinLibrary.uniqueName - Name.special("<$libraryName>") - } - - override val platform: TargetPlatform = NativePlatforms.unspecifiedNativePlatform - override fun dependencies(): List<ModuleInfo> = listOf(this) + dependencyResolver.resolveDependencies(this) - override fun getLibraryRoots(): Collection<String> = listOf(libraryRoot) - - override val capabilities: Map<ModuleCapability<*>, Any?> - get() { - val capabilities = super.capabilities.toMutableMap() - capabilities[KlibModuleOrigin.CAPABILITY] = DeserializedKlibModuleOrigin(kotlinLibrary) - capabilities[ImplicitIntegerCoercion.MODULE_CAPABILITY] = kotlinLibrary.safeRead(false) { isInterop } - return capabilities - } - - private fun <T> KotlinLibrary.safeRead(defaultValue: T, action: KotlinLibrary.() -> T) = try { - action() - } catch (_: IOException) { - defaultValue - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt deleted file mode 100644 index 6063ae1b..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/resolve/DokkaNativeResolverForModuleFactory.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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 -import org.jetbrains.kotlin.container.get -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.incremental.components.LookupTracker -import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories -import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer -import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer -import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider -import org.jetbrains.kotlin.resolve.TargetEnvironment -import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices -import org.jetbrains.kotlin.resolve.lazy.AbsentDescriptorHandler -import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService -import org.jetbrains.kotlin.resolve.scopes.optimization.OptimizingOptions - -/** TODO: replace by [NativeResolverForModuleFactory] after fix of KT-40734 */ -internal class DokkaNativeResolverForModuleFactory( - private val targetEnvironment: TargetEnvironment, - private val kLibService: KLibService, -) : ResolverForModuleFactory() { - companion object { - private val metadataFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer) - } - - override fun <M : ModuleInfo> createResolverForModule( - moduleDescriptor: ModuleDescriptorImpl, - moduleContext: ModuleContext, - moduleContent: ModuleContent<M>, - resolverForProject: ResolverForProject<M>, - languageVersionSettings: LanguageVersionSettings, - sealedInheritorsProvider: SealedClassInheritorsProvider, - resolveOptimizingOptions: OptimizingOptions?, - absentDescriptorHandlerClass: Class<out AbsentDescriptorHandler>? - ): ResolverForModule { - - val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory( - moduleContext.project, - moduleContext.storageManager, - moduleContent.syntheticFiles, - moduleContent.moduleContentScope, - moduleContent.moduleInfo - ) - - val container = createContainerForLazyResolve( - moduleContext = moduleContext, - declarationProviderFactory = declarationProviderFactory, - bindingTrace = CodeAnalyzerInitializer.getInstance(moduleContext.project).createTrace(), - platform = moduleDescriptor.platform!!, - analyzerServices = NativePlatformAnalyzerServices, - targetEnvironment = targetEnvironment, - languageVersionSettings = languageVersionSettings, - absentDescriptorHandlerClass = absentDescriptorHandlerClass - ) - - var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider - - 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 = - CompositePackageFragmentProvider(listOf(packageFragmentProvider, klibPackageFragmentProvider), "DokkaCompositePackageFragmentProvider") - } - - return ResolverForModule(packageFragmentProvider, container) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt deleted file mode 100644 index 95295cf1..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorFullClassHierarchyBuilder.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl - -import com.intellij.psi.PsiClass -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.dokka.analysis.kotlin.internal.ClassHierarchy -import org.jetbrains.dokka.analysis.kotlin.internal.FullClassHierarchyBuilder -import org.jetbrains.dokka.analysis.kotlin.internal.Supertypes -import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters -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 - -internal class DescriptorFullClassHierarchyBuilder : FullClassHierarchyBuilder { - - override suspend fun build(module: DModule): ClassHierarchy = coroutineScope { - val map = module.sourceSets.associateWith { ConcurrentHashMap<DRI, List<DRI>>() } - module.packages.parallelForEach { visitDocumentable(it, map) } - map - } - - private suspend fun collectSupertypesFromKotlinType( - driWithKType: Pair<DRI, KotlinType>, - supersMap: MutableMap<DRI, Supertypes> - ): Unit = coroutineScope { - val (dri, kotlinType) = driWithKType - val supertypes = kotlinType.immediateSupertypes().filterNot { it.isAnyOrNullableAny() } - val supertypesDriWithKType = supertypes.mapNotNull { supertype -> - supertype.constructor.declarationDescriptor?.let { - DRI.from(it) to supertype - } - } - - if (supersMap[dri] == null) { - // another thread can rewrite the same value, but it isn't a problem - supersMap[dri] = supertypesDriWithKType.map { it.first } - supertypesDriWithKType.parallelForEach { collectSupertypesFromKotlinType(it, supersMap) } - } - } - - private suspend fun collectSupertypesFromPsiClass( - driWithPsiClass: Pair<DRI, PsiClass>, - supersMap: MutableMap<DRI, Supertypes> - ): Unit = coroutineScope { - val (dri, psiClass) = driWithPsiClass - val supertypes = psiClass.superTypes.mapNotNull { it.resolve() } - .filterNot { it.qualifiedName == "java.lang.Object" } - val supertypesDriWithPsiClass = supertypes.map { DRI.from(it) to it } - - if (supersMap[dri] == null) { - // another thread can rewrite the same value, but it isn't a problem - supersMap[dri] = supertypesDriWithPsiClass.map { it.first } - supertypesDriWithPsiClass.parallelForEach { collectSupertypesFromPsiClass(it, supersMap) } - } - } - - private suspend fun visitDocumentable( - documentable: Documentable, - hierarchy: SourceSetDependent<MutableMap<DRI, List<DRI>>> - ): Unit = coroutineScope { - if (documentable is WithScope) { - documentable.classlikes.parallelForEach { visitDocumentable(it, hierarchy) } - } - if (documentable is DClasslike) { - // to build a full class graph, using supertypes from Documentable - // is not enough since it keeps only one level of hierarchy - documentable.sources.forEach { (sourceSet, source) -> - if (source is DescriptorDocumentableSource) { - val descriptor = source.descriptor as? ClassifierDescriptorWithTypeParameters ?: return@forEach // it can be typealias as well - val type = descriptor.defaultType - hierarchy[sourceSet]?.let { collectSupertypesFromKotlinType(documentable.dri to type, it) } - } else if (source is PsiDocumentableSource) { - val psi = source.psi as PsiClass - hierarchy[sourceSet]?.let { collectSupertypesFromPsiClass(documentable.dri to psi, it) } - } - } - } - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt deleted file mode 100644 index 46974dce..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorInheritanceBuilder.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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.dokka.analysis.kotlin.internal.InheritanceBuilder -import org.jetbrains.dokka.analysis.kotlin.internal.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<DRI, Documentable>): List<InheritanceNode> { - val descriptorMap = getDescriptorMap(documentables) - - val psiInheritanceTree = - documentables.flatMap { (_, v) -> (v as? WithSources)?.sources?.values.orEmpty() } - .filterIsInstance<PsiDocumentableSource>().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<Pair<PsiClass, List<PsiClass>>> = psi.supers.toList().let { l -> - listOf(psi to l) + l.flatMap { gatherPsiClasses(it) } - } - - private fun getDescriptorMap(documentables: Map<DRI, Documentable>): Map<DRI, ClassDescriptor> { - val map: MutableMap<DRI, ClassDescriptor> = 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<DRI, ClassDescriptor>) { - 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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt deleted file mode 100644 index b022e0c3..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorKotlinToJavaMapper.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.PointingToDeclaration -import org.jetbrains.dokka.analysis.kotlin.internal.KotlinToJavaService -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName - -internal class DescriptorKotlinToJavaMapper : KotlinToJavaService { - - 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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt deleted file mode 100644 index d6768eca..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/DescriptorSyntheticDocumentableDetector.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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.dokka.analysis.kotlin.internal.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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/KotlinSampleProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/KotlinSampleProvider.kt deleted file mode 100644 index 5199abf5..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/KotlinSampleProvider.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl - -import com.intellij.psi.PsiElement -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -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.SamplesKotlinAnalysis -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProvider -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProviderFactory -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.lazy.ResolveSession - -public class KotlinSampleProviderFactory( - public val context: DokkaContext -): SampleProviderFactory { - override fun build(): SampleProvider { - return KotlinSampleProvider(context) - } - -} -/** - * It's declared as open since StdLib has its own sample transformer - * with [processBody] and [processImports] - */ -@InternalDokkaApi -public open class KotlinSampleProvider( - public val context: DokkaContext -): SampleProvider { - private val kDocFinder: KDocFinder = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kdocFinder } - private val analysis = lazy { - /** - * Run from the thread of [Dispatchers.Default]. It can help to avoid a memory leaks in `ThreadLocal`s (that keep `URLCLassLoader`) - * since we shut down Dispatchers.Default at the end of each task (see [org.jetbrains.dokka.DokkaConfiguration.finalizeCoroutines]). - * Currently, all `ThreadLocal`s are in a compiler/IDE codebase. - */ - runBlocking(Dispatchers.Default) { - @OptIn(DokkaPluginApiPreview::class) - SamplesKotlinAnalysis( - sourceSets = context.configuration.sourceSets, - context = context, - projectKotlinAnalysis = context.plugin<CompilerDescriptorAnalysisPlugin>() - .querySingle { kotlinAnalysis } - ) - } - } - protected open fun processBody(psiElement: PsiElement): String { - val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd() - val lines = text.split("\n") - val indent = lines.filter(String::isNotBlank).map { it.takeWhile(Char::isWhitespace).count() }.minOrNull() ?: 0 - return lines.joinToString("\n") { it.drop(indent) } - } - - private fun processSampleBody(psiElement: PsiElement): String = when (psiElement) { - is KtDeclarationWithBody -> { - when (val bodyExpression = psiElement.bodyExpression) { - is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") - else -> bodyExpression!!.text - } - } - else -> psiElement.text - } - - protected open fun processImports(psiElement: PsiElement): String { - val psiFile = psiElement.containingFile - return when(val text = (psiFile as? KtFile)?.importList?.text) { - is String -> text - else -> "" - } - } - - /** - * @return [SampleProvider.SampleSnippet] or null if it has not found by [fqLink] - */ - override fun getSample(sourceSet: DokkaConfiguration.DokkaSourceSet, fqLink: String): SampleProvider.SampleSnippet? { - return runBlocking(Dispatchers.Default) { - val resolveSession = analysis.value[sourceSet].resolveSession - val psiElement = fqNameToPsiElement(resolveSession, fqLink, sourceSet) - ?: return@runBlocking null.also { context.logger.warn("Cannot find PsiElement corresponding to $fqLink") } - val imports = - processImports(psiElement) - val body = processBody(psiElement) - return@runBlocking SampleProvider.SampleSnippet(imports, body) - } - } - override fun close() { - if(analysis.isInitialized()) - analysis.value.close() - } - - private fun fqNameToPsiElement(resolveSession: ResolveSession, functionName: String, dokkaSourceSet: DokkaConfiguration.DokkaSourceSet): PsiElement? { - val packageName = functionName.takeWhile { it != '.' } - val descriptor = resolveSession.getPackageFragment(FqName(packageName)) - ?: return null.also { context.logger.warn("Cannot find descriptor for package $packageName") } - - with (kDocFinder) { - val symbol = resolveKDocLink( - descriptor, - functionName, - dokkaSourceSet, - emptyBindingContext = true - ).firstOrNull() ?: return null.also { context.logger.warn("Unresolved function $functionName in @sample") } - return org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration(symbol) - } - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt deleted file mode 100644 index 98eabf19..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/IllegalModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -import org.jetbrains.dokka.DokkaException - -internal class IllegalModuleAndPackageDocumentation( - source: ModuleAndPackageDocumentationSource, message: String -) : DokkaException("[$source] $message") diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt deleted file mode 100644 index 9b352c1a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -import org.jetbrains.dokka.model.doc.DocumentationNode - -internal data class ModuleAndPackageDocumentation( - val name: String, - val classifier: Classifier, - val documentation: DocumentationNode -) { - enum class Classifier { Module, Package } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt deleted file mode 100644 index d1e729b2..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationFragment.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - - -internal data class ModuleAndPackageDocumentationFragment( - val name: String, - val classifier: ModuleAndPackageDocumentation.Classifier, - val documentation: String, - val source: ModuleAndPackageDocumentationSource -) diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt deleted file mode 100644 index 95701964..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationParsingContext.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -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.jb.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.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name - -internal fun interface ModuleAndPackageDocumentationParsingContext { - fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment, location: String): MarkdownParser -} - -internal fun ModuleAndPackageDocumentationParsingContext.parse( - fragment: ModuleAndPackageDocumentationFragment -): DocumentationNode { - return markdownParserFor(fragment, fragment.source.sourceDescription).parse(fragment.documentation) -} - -internal fun ModuleAndPackageDocumentationParsingContext( - logger: DokkaLogger, - moduleDescriptor: ModuleDescriptor? = null, - kDocFinder: KDocFinder? = null, - sourceSet: DokkaConfiguration.DokkaSourceSet? = null -) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation -> - val descriptor = when (fragment.classifier) { - Module -> moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier(""))) - Package -> moduleDescriptor?.getPackage(FqName(fragment.name)) - } - - val externalDri = { link: String -> - try { - 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") - null - } - } - - MarkdownParser(externalDri = externalDri, sourceLocation) -} - -private fun Collection<DeclarationDescriptor>.sorted() = sortedWith( - compareBy( - { it is ClassDescriptor }, - { (it as? FunctionDescriptor)?.name }, - { (it as? FunctionDescriptor)?.valueParameters?.size }, - { (it as? FunctionDescriptor)?.valueParameters?.joinToString { it.type.toString() } } - ) -) diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt deleted file mode 100644 index e3697159..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationReader.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -import org.jetbrains.dokka.DokkaConfiguration -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 -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Deprecated -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.utilities.associateWithNotNull -import org.jetbrains.dokka.analysis.kotlin.internal.ModuleAndPackageDocumentationReader - -internal fun ModuleAndPackageDocumentationReader(context: DokkaContext): ModuleAndPackageDocumentationReader = - ContextModuleAndPackageDocumentationReader(context) - -private class ContextModuleAndPackageDocumentationReader( - private val context: DokkaContext -) : ModuleAndPackageDocumentationReader { - - private val kotlinAnalysis: KotlinAnalysis = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kotlinAnalysis } - private val kdocFinder: KDocFinder = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kdocFinder } - - private val documentationFragments: SourceSetDependent<List<ModuleAndPackageDocumentationFragment>> = - context.configuration.sourceSets.associateWith { sourceSet -> - sourceSet.includes.flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } - } - - private fun findDocumentationNodes( - sourceSets: Set<DokkaConfiguration.DokkaSourceSet>, - predicate: (ModuleAndPackageDocumentationFragment) -> Boolean - ): SourceSetDependent<DocumentationNode> { - return sourceSets.associateWithNotNull { sourceSet -> - val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate) - val moduleDescriptor = kotlinAnalysis[sourceSet].moduleDescriptor - val documentations = fragments.map { fragment -> - parseModuleAndPackageDocumentation( - context = ModuleAndPackageDocumentationParsingContext(context.logger, moduleDescriptor, kdocFinder, sourceSet), - fragment = fragment - ) - } - when (documentations.size) { - 0 -> null - 1 -> documentations.single().documentation - else -> DocumentationNode(documentations.flatMap { it.documentation.children } - .mergeDocumentationNodes()) - } - } - } - - private val ModuleAndPackageDocumentationFragment.canonicalPackageName: String - get() { - check(classifier == Classifier.Package) - if (name == "[root]") return "" - return name - } - - override fun read(module: DModule): SourceSetDependent<DocumentationNode> { - return findDocumentationNodes(module.sourceSets) { fragment -> - fragment.classifier == Classifier.Module && (fragment.name == module.name) - } - } - - override fun read(pkg: DPackage): SourceSetDependent<DocumentationNode> { - 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<TagWrapper>.mergeDocumentationNodes(): List<TagWrapper> = - groupBy { it::class }.values.map { - it.reduce { acc, tagWrapper -> - val newRoot = CustomDocTag( - acc.children + tagWrapper.children, - name = (tagWrapper as? NamedTagWrapper)?.name.orEmpty() - ) - when (acc) { - is See -> acc.copy(newRoot) - is Param -> acc.copy(newRoot) - is Throws -> acc.copy(newRoot) - is Sample -> acc.copy(newRoot) - is Property -> acc.copy(newRoot) - is CustomTagWrapper -> acc.copy(newRoot) - is Description -> acc.copy(newRoot) - is Author -> acc.copy(newRoot) - is Version -> acc.copy(newRoot) - is Since -> acc.copy(newRoot) - is Return -> acc.copy(newRoot) - is Receiver -> acc.copy(newRoot) - is Constructor -> acc.copy(newRoot) - is Deprecated -> acc.copy(newRoot) - is org.jetbrains.dokka.model.doc.Suppress -> acc.copy(newRoot) - } - } - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt deleted file mode 100644 index 7d717de6..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/ModuleAndPackageDocumentationSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -import java.io.File - -internal abstract class ModuleAndPackageDocumentationSource { - abstract val sourceDescription: String - abstract val documentation: String - override fun toString(): String = sourceDescription -} - -internal data class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { - override val sourceDescription: String = file.path - override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt deleted file mode 100644 index 286d650a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -internal fun parseModuleAndPackageDocumentation( - context: ModuleAndPackageDocumentationParsingContext, - fragment: ModuleAndPackageDocumentationFragment -): ModuleAndPackageDocumentation { - return ModuleAndPackageDocumentation( - name = fragment.name, - classifier = fragment.classifier, - documentation = context.parse(fragment) - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt deleted file mode 100644 index 2b36225b..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/impl/moduledocs/parseModuleAndPackageDocumentationFragments.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs - -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 - -internal fun parseModuleAndPackageDocumentationFragments(source: File): List<ModuleAndPackageDocumentationFragment> { - return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source)) -} - -internal fun parseModuleAndPackageDocumentationFragments( - source: ModuleAndPackageDocumentationSource -): List<ModuleAndPackageDocumentationFragment> { - val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) - return fragmentStrings - .filter(String::isNotBlank) - .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } -} - -private fun parseModuleAndPackageDocFragment( - source: ModuleAndPackageDocumentationSource, - fragment: String -): ModuleAndPackageDocumentationFragment { - val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) - val firstLine = firstLineAndDocumentation[0] - - val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) - - val classifier = when (classifierAndName[0].trim()) { - "Module" -> Module - "Package" -> Package - else -> throw IllegalStateException( - """Unexpected classifier: "${classifierAndName[0]}", expected either "Module" or "Package". - |For more information consult the specification: https://kotlinlang.org/docs/dokka-module-and-package-docs.html""".trimMargin() - ) - } - - if (classifierAndName.size != 2 && classifier == Module) { - throw IllegalModuleAndPackageDocumentation(source, "Missing Module name") - } - - val name = classifierAndName.getOrNull(1)?.trim().orEmpty() - if (classifier == Package && name.contains(Regex("\\s"))) { - throw IllegalModuleAndPackageDocumentation( - source, "Package name cannot contain whitespace in '$firstLine'" - ) - } - - return ModuleAndPackageDocumentationFragment( - name = name, - classifier = classifier, - documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty(), - source = source - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt deleted file mode 100644 index e8dcf63c..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorDocumentationContent.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java - -import org.jetbrains.dokka.analysis.java.doccomment.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<DocumentationContent> { - return listOf(this) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocComment.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocComment.kt deleted file mode 100644 index b6150ca5..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocComment.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java - -import org.jetbrains.dokka.analysis.java.* -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag - -internal class DescriptorKotlinDocComment( - val comment: KDocTag, - val descriptor: DeclarationDescriptor -) : DocComment { - - private val tagsWithContent: List<KDocTag> = 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<DocumentationContent> { - 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<DescriptorDocumentationContent> { - val exceptionName = tag.exceptionQualifiedName ?: return resolveGeneric(tag) - - return comment.children - .filterIsInstance<KDocTag>() - .filter { it.name == tag.name && it.getSubjectName() == exceptionName } - .map { DescriptorDocumentationContent(descriptor, it, tag) } - } - - private fun resolveGeneric(tag: JavadocTag): List<DescriptorDocumentationContent> { - 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 DescriptorKotlinDocComment - - if (comment != other.comment) return false - if (descriptor.name != other.descriptor.name) return false - if (tagsWithContent != other.tagsWithContent) return false - - return true - } - - override fun hashCode(): Int { - var result = comment.hashCode() - result = 31 * result + descriptor.name.hashCode() - result = 31 * result + tagsWithContent.hashCode() - return result - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentCreator.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentCreator.kt deleted file mode 100644 index 6beaac3f..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentCreator.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.doccomment.DocCommentCreator -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.DescriptorFinder -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement - -internal class DescriptorKotlinDocCommentCreator( - private val kdocFinder: KDocFinder, - private val descriptorFinder: DescriptorFinder -) : 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 (descriptorFinder) { - (element.navigationElement as? KtDeclaration)?.findDescriptor() - } ?: return null - - return DescriptorKotlinDocComment(kdoc, descriptor) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentParser.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentParser.kt deleted file mode 100644 index 694ee5ac..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/DescriptorKotlinDocCommentParser.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.parsers.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 DescriptorKotlinDocCommentParser( - private val context: DokkaContext, - private val logger: DokkaLogger -) : DocCommentParser { - - override fun canParse(docComment: DocComment): Boolean { - return docComment is DescriptorKotlinDocComment - } - - override fun parse(docComment: DocComment, context: PsiNamedElement): DocumentationNode { - val kotlinDocComment = docComment as DescriptorKotlinDocComment - return parseDocumentation(kotlinDocComment) - } - - fun parseDocumentation(element: DescriptorKotlinDocComment, 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<CompilerDescriptorAnalysisPlugin>().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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt deleted file mode 100644 index 33ad025f..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisProjectProvider.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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<CompilerDescriptorAnalysisPlugin>().querySingle { kotlinAnalysis } - return kotlinAnalysis[sourceSet].project - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt deleted file mode 100644 index 78b08f18..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinAnalysisSourceRootsExtractor.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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<File> { - val kotlinAnalysis = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kotlinAnalysis } - val environment = kotlinAnalysis[sourceSet].environment - return environment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) - ?.filterIsInstance<JavaSourceRoot>() - ?.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/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt deleted file mode 100644 index 40a12fe8..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/java/KotlinInheritDocTagContentProvider.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.java - -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent -import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin -import org.jetbrains.dokka.analysis.java.parsers.doctag.DocTagParserContext -import org.jetbrains.dokka.analysis.java.parsers.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: DescriptorKotlinDocCommentParser by lazy { - context.plugin<JavaAnalysisPlugin>().query { docCommentParsers } - .single { it is DescriptorKotlinDocCommentParser } as DescriptorKotlinDocCommentParser - } - - 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( - DescriptorKotlinDocComment(descriptorContent.element, descriptorContent.descriptor), - parseWithChildren = false - ) - val id = docTagParserContext.store(inheritedDocNode) - return """<inheritdoc id="$id"/>""" - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt deleted file mode 100644 index b08eecfc..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/CollectionExtensions.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.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 <T, R : Any> Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R? { - for (element in this) { - val result = transform(element) - if (result != null) { - return result - } - } - return null -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt deleted file mode 100644 index 4d561189..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultDescriptorToDocumentableTranslator.kt +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiNamedElement -import com.intellij.psi.util.PsiLiteralUtil.* -import kotlinx.coroutines.* -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -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.* -import org.jetbrains.dokka.model.AnnotationTarget -import org.jetbrains.dokka.model.Nullable -import org.jetbrains.dokka.model.Visibility -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 -import org.jetbrains.dokka.utilities.parallelMap -import org.jetbrains.dokka.utilities.parallelMapNotNull -import org.jetbrains.kotlin.KtNodeTypes -import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor -import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType -import org.jetbrains.kotlin.builtins.isExtensionFunctionType -import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype -import org.jetbrains.kotlin.codegen.isJvmStaticInObjectOrClassOrInterface -import org.jetbrains.kotlin.descriptors.* -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.js.resolve.diagnostics.findPsi -import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor -import org.jetbrains.kotlin.load.kotlin.toSourceElement -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.calls.components.isVararg -import org.jetbrains.kotlin.resolve.calls.util.getValueArgumentsInParentheses -import org.jetbrains.kotlin.resolve.constants.ConstantValue -import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.LocalClass -import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.NormalClass -import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull -import org.jetbrains.kotlin.resolve.descriptorUtil.parents -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinEnum -import org.jetbrains.kotlin.resolve.source.KotlinSourceElement -import org.jetbrains.kotlin.resolve.source.PsiSourceElement -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 java.nio.file.Paths -import org.jetbrains.kotlin.resolve.constants.AnnotationValue as ConstantsAnnotationValue -import org.jetbrains.kotlin.resolve.constants.ArrayValue as ConstantsArrayValue -import org.jetbrains.kotlin.resolve.constants.BooleanValue as ConstantsBooleanValue -import org.jetbrains.kotlin.resolve.constants.DoubleValue as ConstantsDoubleValue -import org.jetbrains.kotlin.resolve.constants.EnumValue as ConstantsEnumValue -import org.jetbrains.kotlin.resolve.constants.FloatValue as ConstantsFloatValue -import org.jetbrains.kotlin.resolve.constants.IntValue as ConstantsIntValue -import org.jetbrains.kotlin.resolve.constants.KClassValue as ConstantsKtClassValue -import org.jetbrains.kotlin.resolve.constants.LongValue as ConstantsLongValue -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 - -internal class DefaultDescriptorToDocumentableTranslator( - private val context: DokkaContext -) : AsyncSourceToDocumentableTranslator, ExternalClasslikesTranslator { - - private val kotlinAnalysis: KotlinAnalysis = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kotlinAnalysis } - private val kdocFinder: KDocFinder = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kdocFinder } - - override suspend fun invokeSuspending(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { - val analysisContext = kotlinAnalysis[sourceSet] - val environment = analysisContext.environment - val packageFragments = environment.getSourceFiles().asSequence() - .map { it.packageFqName } - .distinct() - .mapNotNull { analysisContext.resolveSession.getPackageFragment(it) } - .toList() - - val javadocParser = JavadocParser( - docCommentParsers = context.plugin<JavaAnalysisPlugin>().query { docCommentParsers }, - docCommentFinder = context.plugin<JavaAnalysisPlugin>().docCommentFinder - ) - - - return DokkaDescriptorVisitor(sourceSet, kdocFinder, kotlinAnalysis[sourceSet], context.logger, javadocParser).run { - packageFragments.parallelMap { - visitPackageFragmentDescriptor( - it - ) - } - }.let { - DModule( - name = context.configuration.moduleName, - packages = it, - documentation = emptyMap(), - expectPresentInSet = null, - sourceSets = setOf(sourceSet) - ) - } - } - - /** - * Implementation note: it runs in a separated single thread due to existing support of coroutines (see #2936) - */ - @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class) - override fun translateClassDescriptor(descriptor: ClassDescriptor, sourceSet: DokkaSourceSet): DClasslike { - val driInfo = DRI.from(descriptor.parents.first()).withEmptyInfo() - - val javadocParser = JavadocParser( - docCommentParsers = context.plugin<JavaAnalysisPlugin>().query { docCommentParsers }, - docCommentFinder = context.plugin<JavaAnalysisPlugin>().docCommentFinder - ) - - return newSingleThreadContext("Generating documentable model of classlike").use { coroutineContext -> // see https://github.com/Kotlin/dokka/issues/3151 - runBlocking(coroutineContext) { - DokkaDescriptorVisitor(sourceSet, kdocFinder, kotlinAnalysis[sourceSet], context.logger, javadocParser) - .visitClassDescriptor(descriptor, driInfo) - } - } - } -} - -internal data class DRIWithPlatformInfo( - val dri: DRI, - val actual: SourceSetDependent<DocumentableSource> -) - -internal fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, emptyMap()) - -private class DokkaDescriptorVisitor( - private val sourceSet: DokkaSourceSet, - private val kDocFinder: KDocFinder, - private val analysisContext: AnalysisContext, - private val logger: DokkaLogger, - private val javadocParser: JavadocParser -) { - private val syntheticDocProvider = SyntheticDescriptorDocumentationProvider(kDocFinder, sourceSet) - - private fun Collection<DeclarationDescriptor>.filterDescriptorsInSourceSet() = filter { - it.toSourceElement.containingFile.toString().let { path -> - path.isNotBlank() && sourceSet.sourceRoots.any { root -> - Paths.get(path).startsWith(root.toPath()) - } - } - } - - private fun <T> T.toSourceSetDependent() = if (this != null) mapOf(sourceSet to this) else emptyMap() - - suspend fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor): DPackage { - val name = descriptor.fqName.asString().takeUnless { it.isBlank() } ?: "" - val driWithPlatform = DRI(packageName = name).withEmptyInfo() - val scope = descriptor.getMemberScope() - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind(true) - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - val typealiases = async { descriptorsWithKind.typealiases.visitTypealiases() } - - DPackage( - dri = driWithPlatform.dri, - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - typealiases = typealiases.await(), - documentation = descriptor.resolveDescriptorData(), - sourceSets = setOf(sourceSet) - ) - } - } - - suspend fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClasslike = - when (descriptor.kind) { - ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent) - ClassKind.OBJECT -> objectDescriptor(descriptor, parent) - ClassKind.INTERFACE -> interfaceDescriptor(descriptor, parent) - ClassKind.ANNOTATION_CLASS -> annotationDescriptor(descriptor, parent) - else -> classDescriptor(descriptor, parent) - } - - private suspend fun interfaceDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DInterface { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - val info = descriptor.resolveClassDescriptionData() - - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } - - DInterface( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - generics = generics.await(), - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()), - info.ancestry.exceptionInSupertypesOrNull() - ) - ) - } - } - - private suspend fun objectDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DObject { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - val info = descriptor.resolveClassDescriptionData() - - - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - - DObject( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()), - info.ancestry.exceptionInSupertypesOrNull() - ) - ) - } - - - } - - private suspend fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnum { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - val info = descriptor.resolveClassDescriptionData() - - return coroutineScope { - val descriptorsWithKind = descriptor.getEnumDescriptorsWithKind() - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - val constructors = - async { descriptor.constructors.parallelMap { visitConstructorDescriptor(it, driWithPlatform) } } - val entries = async { descriptorsWithKind.enumEntries.visitEnumEntries(driWithPlatform) } - - DEnum( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - entries = entries.await(), - constructors = constructors.await(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - sources = descriptor.createSources(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - documentation = info.docs, - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()) - ) - ) - } - } - - private fun ClassDescriptor.getEnumDescriptorsWithKind(): DescriptorsWithKind { - val descriptorsWithKind = this.unsubstitutedMemberScope.getDescriptorsWithKind() - val staticScopeForKotlinEnum = (this.staticScope as? StaticScopeForKotlinEnum) ?: return descriptorsWithKind - - // synthetic declarations, such as `entries`, `values()` and `valueOf()`, - // are not present among real in-code declarationg - val contributedDescriptors = staticScopeForKotlinEnum.getContributedDescriptors { true } - return descriptorsWithKind.copy( - properties = descriptorsWithKind.properties + contributedDescriptors.filterIsInstance<PropertyDescriptor>(), - functions = descriptorsWithKind.functions + contributedDescriptors.filterIsInstance<FunctionDescriptor>() - ) - } - - private suspend fun visitEnumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnumEntry { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope - val isExpect = descriptor.isExpect - - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - - DEnumEntry( - dri = driWithPlatform.dri.withEnumEntryExtra(), - name = descriptor.name.asString(), - documentation = descriptor.resolveDescriptorData(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - sourceSets = setOf(sourceSet), - expectPresentInSet = sourceSet.takeIf { isExpect }, - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() - ) - ) - } - } - - private suspend fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() - - val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } - val constructors = - async { descriptor.constructors.parallelMap { visitConstructorDescriptor(it, driWithPlatform) } } - - DAnnotation( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - documentation = descriptor.resolveDescriptorData(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() - ), - companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = generics.await(), - constructors = constructors.await(), - sources = descriptor.createSources() - ) - } - - - } - - private suspend fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClass { - val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - val info = descriptor.resolveClassDescriptionData() - val actual = descriptor.createSources() - - return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() - - val (regularFunctions, accessors) = splitFunctionsAndInheritedAccessors( - properties = descriptorsWithKind.properties, - functions = descriptorsWithKind.functions - ) - - val functions = async { regularFunctions.visitFunctions(driWithPlatform) } - val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform, accessors) } - val classlikes = async { descriptorsWithKind.classlikes.visitClasslikes(driWithPlatform) } - val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } - val constructors = async { - descriptor.constructors.parallelMap { - visitConstructorDescriptor( - it, - if (it.isPrimary) DRIWithPlatformInfo(driWithPlatform.dri, actual) - else DRIWithPlatformInfo(driWithPlatform.dri, emptyMap()) - ) - } - } - - DClass( - dri = driWithPlatform.dri, - name = descriptor.name.asString(), - constructors = constructors.await(), - functions = functions.await(), - properties = properties.await(), - classlikes = classlikes.await(), - sources = actual, - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - supertypes = info.supertypes.toSourceSetDependent(), - generics = generics.await(), - documentation = info.docs, - modifier = descriptor.modifier().toSourceSetDependent(), - companion = descriptor.companion(driWithPlatform), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.ancestry.allImplementedInterfaces().toSourceSetDependent()), - info.ancestry.exceptionInSupertypesOrNull() - ) - ) - } - } - - /** - * @param implicitAccessors getters/setters that are not part of the property descriptor, for instance - * average methods inherited from java sources that access the property - */ - private suspend fun visitPropertyDescriptor( - originalDescriptor: PropertyDescriptor, - implicitAccessors: DescriptorAccessorHolder?, - parent: DRIWithPlatformInfo - ): DProperty { - val (dri, _) = originalDescriptor.createDRI() - val inheritedFrom = dri.getInheritedFromDRI(parent) - val descriptor = originalDescriptor.getConcreteDescriptor() - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - - val actual = originalDescriptor.createSources() - - // example - generated getter that comes with data classes - suspend fun getDescriptorGetter() = - descriptor.accessors - .firstIsInstanceOrNull<PropertyGetterDescriptor>() - ?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri, inheritedFrom) - } - - suspend fun getImplicitAccessorGetter() = - implicitAccessors?.getter?.let { visitFunctionDescriptor(it, parent) } - - // example - generated setter that comes with data classes - suspend fun getDescriptorSetter() = - descriptor.accessors - .firstIsInstanceOrNull<PropertySetterDescriptor>() - ?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri, inheritedFrom) - } - - suspend fun getImplicitAccessorSetter() = - implicitAccessors?.setter?.let { visitFunctionDescriptor(it, parent) } - - return coroutineScope { - val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } - val getter = getDescriptorGetter() ?: getImplicitAccessorGetter() - val setter = getDescriptorSetter() ?: getImplicitAccessorSetter() - - DProperty( - dri = dri, - name = descriptor.name.asString(), - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - sources = actual, - getter = getter, - setter = setter, - visibility = descriptor.getVisibility(implicitAccessors).toSourceSetDependent(), - documentation = descriptor.getDocumentation(), - modifier = descriptor.modifier().toSourceSetDependent(), - type = descriptor.returnType!!.toBound(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - generics = generics.await(), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - listOfNotNull( - (descriptor.additionalExtras() + descriptor.getAnnotationsWithBackingField() - .toAdditionalExtras()).toSet().toSourceSetDependent().toAdditionalModifiers(), - (descriptor.getAnnotationsWithBackingField() + descriptor.fileLevelAnnotations()).toSourceSetDependent() - .toAnnotations(), - 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)) } - ) - ) - ) - } - } - - private fun PropertyDescriptor.isVar(getter: DFunction?, setter: DFunction?): Boolean { - return if (this is JavaPropertyDescriptor) { - // in Java, concepts of extensibility and mutability are mixed into a single `final` modifier - // in Kotlin, it's different - val/var controls mutability and open modifier controls extensibility - // so when inheriting Java properties, you can end up with a final var - non extensible mutable prop - val isMutable = this.isVar - // non-final java property should be var if it has no accessors at all or has a setter - (isMutable && getter == null && setter == null) || (getter != null && setter != null) - } else { - this.isVar - } - } - - private fun PropertyDescriptor.getVisibility(implicitAccessors: DescriptorAccessorHolder?): Visibility { - val isNonPublicJavaProperty = this is JavaPropertyDescriptor && !this.visibility.isPublicAPI - val visibility = - if (isNonPublicJavaProperty) { - // only try to take implicit getter's visibility if it's a java property - // because it's not guaranteed that implicit accessor will be used - // for the kotlin property, as it may have an explicit accessor of its own, - // i.e in data classes or with get() and set() are overridden - (implicitAccessors?.getter?.visibility ?: this.visibility) - } else { - this.visibility - } - - return visibility.toDokkaVisibility() - } - - private fun CallableMemberDescriptor.createDRI(wasOverridenBy: DRI? = null): Pair<DRI, DRI?> = - if (kind == CallableMemberDescriptor.Kind.DECLARATION || overriddenDescriptors.isEmpty()) - Pair(DRI.from(this), wasOverridenBy) - else - overriddenDescriptors.first().createDRI(DRI.from(this)) - - private suspend fun visitFunctionDescriptor( - originalDescriptor: FunctionDescriptor, - parent: DRIWithPlatformInfo - ): DFunction { - val (dri, _) = originalDescriptor.createDRI() - val inheritedFrom = dri.getInheritedFromDRI(parent) - val descriptor = originalDescriptor.getConcreteDescriptor() - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - - val actual = originalDescriptor.createSources() - return coroutineScope { - val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } - - DFunction( - dri = dri, - name = descriptor.name.asString(), - isConstructor = false, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - parameters = descriptor.valueParameters.mapIndexed { index, desc -> - parameter(index, desc, DRIWithPlatformInfo(dri, actual)) - }, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sources = actual, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = generics.await(), - documentation = descriptor.getDocumentation(), - modifier = descriptor.modifier().toSourceSetDependent(), - type = descriptor.returnType!!.toBound(), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - (descriptor.getAnnotations() + descriptor.fileLevelAnnotations()).toSourceSetDependent() - .toAnnotations(), - ObviousMember.takeIf { descriptor.isObvious() }, - ) - ) - } - } - - private fun DeclarationDescriptor.getDocumentation(): SourceSetDependent<DocumentationNode> { - val isSynthesized = this is CallableMemberDescriptor && this.kind == CallableMemberDescriptor.Kind.SYNTHESIZED - return if (isSynthesized) { - syntheticDocProvider.getDocumentation(this)?.toSourceSetDependent() ?: emptyMap() - } else { - this.resolveDescriptorData() - } - } - - /** - * `createDRI` returns the DRI of the exact element and potential DRI of an element that is overriding it - * (It can be also FAKE_OVERRIDE which is in fact just inheritance of the symbol) - * - * Looking at what PSIs do, they give the DRI of the element within the classnames where it is actually - * declared and inheritedFrom as the same DRI but truncated callable part. - * Therefore, we set callable to null and take the DRI only if it is indeed coming from different class. - */ - private fun DRI.getInheritedFromDRI(parent: DRIWithPlatformInfo): DRI? { - return this.copy(callable = null) - .takeIf { parent.dri.classNames != this.classNames || parent.dri.packageName != this.packageName } - } - - private fun FunctionDescriptor.isObvious(): Boolean { - return kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE - || (kind == CallableMemberDescriptor.Kind.SYNTHESIZED && !syntheticDocProvider.isDocumented(this)) - || containingDeclaration.fqNameOrNull()?.isObvious() == true - } - - private fun FqName.isObvious(): Boolean = with(this.asString()) { - return this == "kotlin.Any" || this == "kotlin.Enum" - || this == "java.lang.Object" || this == "java.lang.Enum" - } - - suspend fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): DFunction { - val name = descriptor.constructedClass.name.toString() - val dri = parent.dri.copy(callable = Callable.from(descriptor, name)) - val actual = descriptor.createSources() - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - - return coroutineScope { - val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } - - DFunction( - dri = dri, - name = name, - isConstructor = true, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor(it, DRIWithPlatformInfo(dri, actual)) - }, - parameters = descriptor.valueParameters.mapIndexed { index, desc -> - parameter(index, desc, DRIWithPlatformInfo(dri, actual)) - }, - sources = actual, - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = descriptor.resolveDescriptorData().let { sourceSetDependent -> - if (descriptor.isPrimary) { - sourceSetDependent.map { entry -> - Pair( - entry.key, - entry.value.copy(children = (entry.value.children.find { it is Constructor }?.root?.let { constructor -> - listOf(Description(constructor)) - } ?: emptyList<TagWrapper>()) + entry.value.children.filterIsInstance<Param>())) - }.toMap() - } else { - sourceSetDependent - } - }, - type = descriptor.returnType.toBound(), - modifier = descriptor.modifier().toSourceSetDependent(), - generics = generics.await(), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll<DFunction>( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() - ).let { - if (descriptor.isPrimary) { - it + PrimaryConstructorExtra - } else it - } - ) - } - } - - private suspend fun visitReceiverParameterDescriptor( - descriptor: ReceiverParameterDescriptor, - parent: DRIWithPlatformInfo - ) = DParameter( - dri = parent.dri.copy(target = PointingToDeclaration), - name = null, - type = descriptor.type.toBound(), - expectPresentInSet = null, - documentation = descriptor.resolveDescriptorData(), - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll(descriptor.getAnnotations().toSourceSetDependent().toAnnotations()) - ) - - private suspend fun visitPropertyAccessorDescriptor( - descriptor: PropertyAccessorDescriptor, - propertyDescriptor: PropertyDescriptor, - parent: DRI, - inheritedFrom: DRI? = null - ): DFunction { - val dri = parent.copy(callable = Callable.from(descriptor)) - val isGetter = descriptor is PropertyGetterDescriptor - val isExpect = descriptor.isExpect - val isActual = descriptor.isActual - - suspend fun PropertyDescriptor.asParameter(parent: DRI) = - DParameter( - parent.copy(target = PointingToCallableParameters(parameterIndex = 1)), - this.name.asString(), - type = this.type.toBound(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - documentation = descriptor.resolveDescriptorData(), - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - getAnnotationsWithBackingField().toSourceSetDependent().toAnnotations() - ) - ) - - val name = run { - val rawName = propertyDescriptor.name.asString() - /* - * Kotlin has special rules for conversion around properties that - * start with "is" For more info see: - * https://kotlinlang.org/docs/java-interop.html#getters-and-setters - * https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties - * - * Based on our testing, this rule only applies when the letter after - * the "is" is *not* lowercase. This means that words like "issue" won't - * have the rule applied but "is_foobar" and "is1of" will have the rule applied. - */ - val specialCaseIs = rawName.startsWith("is") - && rawName.getOrNull(2)?.isLowerCase() == false - - if (specialCaseIs) { - if (isGetter) rawName else rawName.replaceFirst("is", "set") - } else { - if (isGetter) "get${rawName.capitalize()}" else "set${rawName.capitalize()}" - } - } - - val parameters = - if (isGetter) { - emptyList() - } else { - listOf(propertyDescriptor.asParameter(dri)) - } - - return coroutineScope { - val generics = async { descriptor.typeParameters.parallelMap { it.toVariantTypeParameter() } } - DFunction( - dri, - name, - isConstructor = false, - parameters = parameters, - visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = descriptor.resolveDescriptorData().mapInheritedTagWrappers(), - type = descriptor.returnType!!.toBound(), - generics = generics.await(), - modifier = descriptor.modifier().toSourceSetDependent(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - receiver = descriptor.extensionReceiverParameter?.let { - visitReceiverParameterDescriptor( - it, - DRIWithPlatformInfo(dri, descriptor.createSources()) - ) - }, - sources = descriptor.createSources(), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) } - ) - ) - } - } - - /** - * Workaround for a problem with inheriting parent TagWrappers of the wrong type. - * - * For instance, if you annotate a class with `@property`, kotlin compiler will propagate - * this tag to the property and its getters and setters. In case of getters and setters, - * it's more correct to display propagated docs as description instead of property - */ - private fun SourceSetDependent<DocumentationNode>.mapInheritedTagWrappers(): SourceSetDependent<DocumentationNode> { - return this.mapValues { (_, value) -> - val mappedChildren = value.children.map { - when (it) { - is Property -> Description(it.root) - else -> it - } - } - value.copy(children = mappedChildren) - } - } - - private suspend fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor) = - with(descriptor) { - coroutineScope { - val generics = async { descriptor.declaredTypeParameters.parallelMap { it.toVariantTypeParameter() } } - val info = buildAncestryInformation(defaultType).copy( - superclass = buildAncestryInformation(underlyingType), - interfaces = emptyList() - ) - DTypeAlias( - dri = DRI.from(this@with), - name = name.asString(), - type = defaultType.toBound(), - expectPresentInSet = null, - underlyingType = underlyingType.toBound().toSourceSetDependent(), - visibility = visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = resolveDescriptorData(), - sourceSets = setOf(sourceSet), - generics = generics.await(), - sources = descriptor.createSources(), - extra = PropertyContainer.withAll( - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - info.exceptionInSupertypesOrNull(), - ) - ) - } - } - - private suspend fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = - DParameter( - dri = parent.dri.copy(target = PointingToCallableParameters(index)), - name = descriptor.name.asString(), - type = descriptor.varargElementType?.toBound() ?: descriptor.type.toBound(), - expectPresentInSet = null, - documentation = descriptor.resolveDescriptorData(), - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll(listOfNotNull( - descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - descriptor.getDefaultValue()?.let { DefaultValue(it.toSourceSetDependent()) } - )) - ) - - private data class DescriptorsWithKind( - val functions: List<FunctionDescriptor>, - val properties: List<PropertyDescriptor>, - val classlikes: List<ClassDescriptor>, - val typealiases: List<TypeAliasDescriptor>, - val enumEntries: List<ClassDescriptor> - ) - - private fun MemberScope.getDescriptorsWithKind(shouldFilter: Boolean = false): DescriptorsWithKind { - val descriptors = getContributedDescriptors { true }.let { - if (shouldFilter) it.filterDescriptorsInSourceSet() else it - } - - class EnumEntryDescriptor - - val groupedDescriptors = descriptors.groupBy { - when { - it is FunctionDescriptor -> FunctionDescriptor::class - it is PropertyDescriptor -> PropertyDescriptor::class - it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY -> ClassDescriptor::class - it is TypeAliasDescriptor -> TypeAliasDescriptor::class - it is ClassDescriptor && it.kind == ClassKind.ENUM_ENTRY -> EnumEntryDescriptor::class - else -> IllegalStateException::class - } - } - - @Suppress("UNCHECKED_CAST") - return DescriptorsWithKind( - (groupedDescriptors[FunctionDescriptor::class] ?: emptyList()) as List<FunctionDescriptor>, - (groupedDescriptors[PropertyDescriptor::class] ?: emptyList()) as List<PropertyDescriptor>, - (groupedDescriptors[ClassDescriptor::class] ?: emptyList()) as List<ClassDescriptor>, - (groupedDescriptors[TypeAliasDescriptor::class] ?: emptyList()) as List<TypeAliasDescriptor>, - (groupedDescriptors[EnumEntryDescriptor::class] ?: emptyList()) as List<ClassDescriptor> - ) - } - - private suspend fun List<FunctionDescriptor>.visitFunctions(parent: DRIWithPlatformInfo): List<DFunction> = - coroutineScope { parallelMap { visitFunctionDescriptor(it, parent) } } - - private suspend fun List<PropertyDescriptor>.visitProperties( - parent: DRIWithPlatformInfo, - implicitAccessors: Map<PropertyDescriptor, DescriptorAccessorHolder> = emptyMap(), - ): List<DProperty> { - return coroutineScope { - parallelMap { - visitPropertyDescriptor(it, implicitAccessors[it], parent) - } - } - } - - private suspend fun List<ClassDescriptor>.visitClasslikes(parent: DRIWithPlatformInfo): List<DClasslike> = - coroutineScope { parallelMap { visitClassDescriptor(it, parent) } } - - private suspend fun List<TypeAliasDescriptor>.visitTypealiases(): List<DTypeAlias> = - coroutineScope { parallelMap { visitTypeAliasDescriptor(it) } } - - private suspend fun List<ClassDescriptor>.visitEnumEntries(parent: DRIWithPlatformInfo): List<DEnumEntry> = - coroutineScope { parallelMap { visitEnumEntryDescriptor(it, parent) } } - - private fun DeclarationDescriptor.resolveDescriptorData(): SourceSetDependent<DocumentationNode> = - resolveDocumentation()?.toSourceSetDependent() ?: emptyMap() - - - private suspend fun toTypeConstructor(kt: KotlinType) = - GenericTypeConstructor( - DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), - kt.arguments.map { it.toProjection() }, - extra = PropertyContainer.withAll(kt.getAnnotations().toSourceSetDependent().toAnnotations()) - ) - - private suspend fun buildAncestryInformation( - kotlinType: KotlinType - ): AncestryNode { - val (interfaces, superclass) = kotlinType.immediateSupertypes().filterNot { it.isAnyOrNullableAny() } - .partition { - val declaration = it.constructor.declarationDescriptor - val descriptor = declaration as? ClassDescriptor - ?: (declaration as? TypeAliasDescriptor)?.underlyingType?.constructor?.declarationDescriptor as? ClassDescriptor - descriptor?.kind == ClassKind.INTERFACE - } - - return coroutineScope { - AncestryNode( - typeConstructor = toTypeConstructor(kotlinType), - superclass = superclass.parallelMap(::buildAncestryInformation).singleOrNull(), - interfaces = interfaces.parallelMap(::buildAncestryInformation) - ) - } - } - - - private suspend fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { - return coroutineScope { - ClassInfo( - buildAncestryInformation(this@resolveClassDescriptionData.defaultType), - resolveDescriptorData() - ) - } - } - - private suspend fun TypeParameterDescriptor.toVariantTypeParameter() = - DTypeParameter( - variantTypeParameter( - TypeParameter(DRI.from(this), name.identifier, annotations.getPresentableName()) - ), - resolveDescriptorData(), - null, - upperBounds.map { it.toBound() }, - setOf(sourceSet), - extra = PropertyContainer.withAll( - additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - getAnnotations().toSourceSetDependent().toAnnotations() - ) - ) - - private fun org.jetbrains.kotlin.descriptors.annotations.Annotations.getPresentableName(): String? = - mapNotNull { it.toAnnotation() }.singleOrNull { it.dri.classNames == "ParameterName" }?.params?.get("name") - .let { it as? StringValue }?.value?.let { unquotedValue(it) } - - private suspend fun KotlinType.toBound(): Bound { - suspend fun <T : AnnotationTarget> annotations(): PropertyContainer<T> = - getAnnotations().takeIf { it.isNotEmpty() }?.let { annotations -> - PropertyContainer.withAll(annotations.toSourceSetDependent().toAnnotations()) - } ?: PropertyContainer.empty() - - return when (this) { - is DynamicType -> Dynamic - is AbbreviatedType -> TypeAliased( - abbreviation.toBound(), - expandedType.toBound(), - annotations() - ) - is DefinitelyNotNullType -> DefinitelyNonNullable( - original.toBound() - ) - else -> when (val ctor = constructor.declarationDescriptor) { - is TypeParameterDescriptor -> TypeParameter( - dri = DRI.from(ctor), - name = ctor.name.asString(), - presentableName = annotations.getPresentableName(), - extra = annotations() - ) - is FunctionClassDescriptor -> FunctionalTypeConstructor( - DRI.from(ctor), - arguments.map { it.toProjection() }, - isExtensionFunction = isExtensionFunctionType || isBuiltinExtensionFunctionalType, - isSuspendable = isSuspendFunctionTypeOrSubtype, - presentableName = annotations.getPresentableName(), - extra = annotations() - ) - else -> GenericTypeConstructor( - DRI.from(ctor!!), // TODO: remove '!!' - arguments.map { it.toProjection() }, - annotations.getPresentableName(), - extra = annotations() - ) - }.let { - if (isMarkedNullable) Nullable(it) else it - } - } - } - - private suspend fun TypeProjection.toProjection(): Projection = - if (isStarProjection) Star else formPossiblyVariant() - - private suspend fun TypeProjection.formPossiblyVariant(): Projection = - type.toBound().wrapWithVariance(projectionKind) - - private fun TypeParameterDescriptor.variantTypeParameter(type: TypeParameter) = - type.wrapWithVariance(variance) - - private fun <T : Bound> T.wrapWithVariance(variance: org.jetbrains.kotlin.types.Variance) = - when (variance) { - org.jetbrains.kotlin.types.Variance.INVARIANT -> Invariance(this) - org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Contravariance(this) - org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Covariance(this) - } - - private fun descriptorToAnyDeclaration(descriptor: DeclarationDescriptor): PsiElement? { - val effectiveReferencedDescriptors = DescriptorToSourceUtils.getEffectiveReferencedDescriptors(descriptor) - //take any - return effectiveReferencedDescriptors.firstOrNull()?.let { DescriptorToSourceUtils.getSourceFromDescriptor(it) } - } - - private fun DeclarationDescriptor.resolveDocumentation(): DocumentationNode? { - val find = with(kDocFinder) { - find(::descriptorToAnyDeclaration) - } - - return (find?.let { - parseFromKDocTag( - kDocTag = it, - externalDri = { link: String -> - try { - val kdocLink = with(kDocFinder) { - resolveKDocLink( - fromDescriptor = this@resolveDocumentation, - 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() - val allDescriptors = overriddenDescriptors + listOf(this) - return allDescriptors - .mapNotNull { it.findPsi() as? PsiNamedElement } - .firstOrNull() - ?.let { javadocParser.parseDocumentation(it) } - } - - private suspend fun ClassDescriptor.companion(dri: DRIWithPlatformInfo): DObject? = companionObjectDescriptor?.let { - objectDescriptor(it, dri) - } - - private fun MemberDescriptor.modifier() = when (modality) { - Modality.FINAL -> KotlinModifier.Final - Modality.SEALED -> KotlinModifier.Sealed - Modality.OPEN -> KotlinModifier.Open - Modality.ABSTRACT -> KotlinModifier.Abstract - else -> KotlinModifier.Empty - } - - private fun MemberDescriptor.createSources(): SourceSetDependent<DocumentableSource> = - DescriptorDocumentableSource(this).toSourceSetDependent() - - private fun FunctionDescriptor.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Infix.takeIf { isInfix }, - ExtraModifiers.KotlinOnlyModifiers.Inline.takeIf { isInline }, - ExtraModifiers.KotlinOnlyModifiers.Suspend.takeIf { isSuspend }, - ExtraModifiers.KotlinOnlyModifiers.Operator.takeIf { isOperator }, - ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - ExtraModifiers.KotlinOnlyModifiers.TailRec.takeIf { isTailrec }, - ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { DescriptorUtils.isOverride(this) } - ).toSet() - - private fun ClassDescriptor.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Inline.takeIf { isInline }, - ExtraModifiers.KotlinOnlyModifiers.Value.takeIf { isValue }, - ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - ExtraModifiers.KotlinOnlyModifiers.Inner.takeIf { isInner }, - ExtraModifiers.KotlinOnlyModifiers.Data.takeIf { isData }, - ExtraModifiers.KotlinOnlyModifiers.Fun.takeIf { isFun }, - ).toSet() - - private fun ValueParameterDescriptor.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.NoInline.takeIf { isNoinline }, - ExtraModifiers.KotlinOnlyModifiers.CrossInline.takeIf { isCrossinline }, - ExtraModifiers.KotlinOnlyModifiers.Const.takeIf { isConst }, - ExtraModifiers.KotlinOnlyModifiers.LateInit.takeIf { isLateInit }, - ExtraModifiers.KotlinOnlyModifiers.VarArg.takeIf { isVararg } - ).toSet() - - private fun TypeParameterDescriptor.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Reified.takeIf { isReified } - ).toSet() - - private fun PropertyDescriptor.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Const.takeIf { isConst }, - ExtraModifiers.KotlinOnlyModifiers.LateInit.takeIf { isLateInit }, - ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { DescriptorUtils.isOverride(this) } - ) - - private suspend fun Annotated.getAnnotations() = annotations.parallelMapNotNull { it.toAnnotation() } - - private fun ConstantValue<*>.toValue(): AnnotationParameterValue = when (this) { - is ConstantsAnnotationValue -> AnnotationValue(value.toAnnotation()) - is ConstantsArrayValue -> ArrayValue(value.map { it.toValue() }) - is ConstantsEnumValue -> EnumValue( - fullEnumEntryName(), - DRI(enumClassId.packageFqName.asString(), fullEnumEntryName()) - ) - is ConstantsKtClassValue -> when (val value = value) { - is NormalClass -> value.classId.let { - ClassValue( - it.relativeClassName.asString(), - DRI(it.packageFqName.asString(), it.relativeClassName.asString()) - ) - } - is LocalClass -> value.type.let { - ClassValue( - it.toString(), - DRI.from(it.constructor.declarationDescriptor as DeclarationDescriptor) - ) - } - } - is ConstantsFloatValue -> FloatValue(value) - is ConstantsDoubleValue -> DoubleValue(value) - is ConstantsUIntValue -> IntValue(value) - is ConstantsULongValue -> LongValue(value) - is ConstantsIntValue -> IntValue(value) - is ConstantsLongValue -> LongValue(value) - is ConstantsBooleanValue -> BooleanValue(value) - is ConstantsNullValue -> NullValue - else -> StringValue(unquotedValue(toString())) - } - - private fun AnnotationDescriptor.toAnnotation(scope: Annotations.AnnotationScope = Annotations.AnnotationScope.DIRECT): Annotations.Annotation = - Annotations.Annotation( - DRI.from(annotationClass as DeclarationDescriptor), - allValueArguments.map { it.key.asString() to it.value.toValue() }.toMap(), - mustBeDocumented(), - scope - ) - - private fun AnnotationDescriptor.mustBeDocumented(): Boolean = - if (source.toString() == "NO_SOURCE") false - else annotationClass?.annotations?.hasAnnotation(FqName("kotlin.annotation.MustBeDocumented")) ?: false - - private suspend fun PropertyDescriptor.getAnnotationsWithBackingField(): List<Annotations.Annotation> = - getAnnotations() + (backingField?.getAnnotations() ?: emptyList()) - - private fun List<Annotations.Annotation>.toAdditionalExtras() = mapNotNull { - try { - ExtraModifiers.valueOf(it.dri.classNames?.toLowerCase() ?: "") - } catch (e: IllegalArgumentException) { - null - } - } - - private fun <T : CallableMemberDescriptor> T.getConcreteDescriptor(): T { - return if (kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - this - } else { - @Suppress("UNCHECKED_CAST") - overriddenDescriptors.first().getConcreteDescriptor() as T - } - } - - private fun ValueParameterDescriptor.getDefaultValue(): Expression? = - ((source as? KotlinSourceElement)?.psi as? KtParameter)?.defaultValue?.toDefaultValueExpression() - - private fun PropertyDescriptor.getDefaultValue(): Expression? = - (source as? KotlinSourceElement)?.psi?.children?.firstIsInstanceOrNull<KtConstantExpression>() - ?.toDefaultValueExpression() - - private fun ClassDescriptor.getAppliedConstructorParameters() = - (source as PsiSourceElement).psi?.children?.flatMap { - (it as? KtInitializerList)?.initializersAsExpression().orEmpty() - }.orEmpty() - - private fun KtInitializerList.initializersAsExpression() = - initializers.firstIsInstanceOrNull<KtCallElement>() - ?.getValueArgumentsInParentheses() - ?.map { it.getArgumentExpression()?.toDefaultValueExpression() ?: ComplexExpression("") } - .orEmpty() - - private fun KtExpression.toDefaultValueExpression(): Expression? = when (node?.elementType) { - KtNodeTypes.INTEGER_CONSTANT -> parseLong(node?.text)?.let { IntegerConstant(it) } - KtNodeTypes.FLOAT_CONSTANT -> if (node?.text?.toLowerCase()?.endsWith('f') == true) - parseFloat(node?.text)?.let { FloatConstant(it) } - else parseDouble(node?.text)?.let { DoubleConstant(it) } - KtNodeTypes.BOOLEAN_CONSTANT -> BooleanConstant(node?.text == "true") - KtNodeTypes.STRING_TEMPLATE -> StringConstant(node.findChildByType(KtNodeTypes.LITERAL_STRING_TEMPLATE_ENTRY)?.text.orEmpty()) - else -> node?.text?.let { ComplexExpression(it) } - } - - private data class ClassInfo(val ancestry: AncestryNode, val docs: SourceSetDependent<DocumentationNode>) { - val supertypes: List<TypeConstructorWithKind> - get() = listOfNotNull(ancestry.superclass?.let { - it.typeConstructor.let { - TypeConstructorWithKind( - it, - KotlinClassKindTypes.CLASS - ) - } - }) + ancestry.interfaces.map { TypeConstructorWithKind(it.typeConstructor, KotlinClassKindTypes.INTERFACE) } - } - - private fun DescriptorVisibility.toDokkaVisibility(): Visibility = when (this.delegate) { - Visibilities.Public -> KotlinVisibility.Public - Visibilities.Protected -> KotlinVisibility.Protected - Visibilities.Internal -> KotlinVisibility.Internal - Visibilities.Private, Visibilities.PrivateToThis -> KotlinVisibility.Private - JavaVisibilities.ProtectedAndPackage -> KotlinVisibility.Protected - JavaVisibilities.ProtectedStaticVisibility -> KotlinVisibility.Protected - JavaVisibilities.PackageVisibility -> JavaVisibility.Default - else -> KotlinVisibility.Public - } - - private fun ConstantsEnumValue.fullEnumEntryName() = - "${this.enumClassId.relativeClassName.asString()}.${this.enumEntryName.identifier}" - - private fun DeclarationDescriptorWithSource.ktFile(): KtFile? = - (source.containingFile as? PsiSourceFile)?.psiFile as? KtFile - - private suspend fun DeclarationDescriptorWithSource.fileLevelAnnotations() = ktFile() - ?.let { file -> - analysisContext.resolveSession.getFileAnnotations(file) - } - ?.toList() - ?.parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) } - .orEmpty() - - private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? = - typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() }?.let { ExceptionInSupertypes(it.toSourceSetDependent()) } -} - diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt deleted file mode 100644 index 006a990b..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DefaultExternalDocumentablesProvider.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -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.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.analysis.kotlin.internal.ExternalDocumentablesProvider -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PackageViewDescriptor -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered - -internal class DefaultExternalDocumentablesProvider(context: DokkaContext) : ExternalDocumentablesProvider { - private val analysis = context.plugin<CompilerDescriptorAnalysisPlugin>().querySingle { kotlinAnalysis } - - 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].moduleDescriptor.getPackage(pkg) - val classDsc = names.fold<String, DeclarationDescriptor?>(packageDsc) { dsc, name -> - dsc?.scope?.getDescriptorsFiltered { it.identifier == name } - ?.filterIsInstance<ClassDescriptor>() - ?.firstOrNull() - } - - return (classDsc as? ClassDescriptor)?.let { translator.translateClassDescriptor(it, sourceSet) } - } - - private val DeclarationDescriptor.scope: MemberScope - get() = when (this) { - is PackageViewDescriptor -> memberScope - is ClassDescriptor -> unsubstitutedMemberScope - else -> throw IllegalArgumentException("Unexpected type of descriptor: ${this::class}") - } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt deleted file mode 100644 index b350e035..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/DescriptorAccessorConventionUtil.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor -import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName -import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName - -internal data class DescriptorFunctionsHolder( - val regularFunctions: List<FunctionDescriptor>, - val accessors: Map<PropertyDescriptor, DescriptorAccessorHolder> -) - -internal data class DescriptorAccessorHolder( - val getter: FunctionDescriptor? = null, - val setter: FunctionDescriptor? = null -) - -/** - * Separate regular Kotlin/Java functions and inherited Java accessors - * to properly display properties inherited from Java. - * - * Take this example: - * ``` - * // java - * public class JavaClass { - * private int a = 1; - * public int getA() { return a; } - * public void setA(int a) { this.a = a; } - * } - * - * // kotlin - * class Bar : JavaClass() { - * fun foo() {} - * } - * ``` - * - * It should result in: - * - 1 regular function `foo` - * - Map a=[`getA`, `setA`] - */ -internal fun splitFunctionsAndInheritedAccessors( - properties: List<PropertyDescriptor>, - functions: List<FunctionDescriptor> -): DescriptorFunctionsHolder { - val (javaMethods, kotlinFunctions) = functions.partition { it is JavaMethodDescriptor } - if (javaMethods.isEmpty()) { - return DescriptorFunctionsHolder(regularFunctions = kotlinFunctions, emptyMap()) - } - - val propertiesByName = properties.associateBy { it.name.asString() } - val regularFunctions = ArrayList<FunctionDescriptor>(kotlinFunctions) - - val accessors = mutableMapOf<PropertyDescriptor, DescriptorAccessorHolder>() - javaMethods.forEach { function -> - val possiblePropertyNamesForFunction = function.toPossiblePropertyNames() - val property = possiblePropertyNamesForFunction.firstNotNullOfOrNull { propertiesByName[it] } - if (property != null && function.isAccessorFor(property)) { - accessors.compute(property) { prop, accessorHolder -> - if (function.isGetterFor(prop)) - accessorHolder?.copy(getter = function) ?: DescriptorAccessorHolder(getter = function) - else - accessorHolder?.copy(setter = function) ?: DescriptorAccessorHolder(setter = function) - } - } else { - regularFunctions.add(function) - } - } - - val accessorLookalikes = removeNonAccessorsReturning(accessors) - regularFunctions.addAll(accessorLookalikes) - - return DescriptorFunctionsHolder(regularFunctions, accessors) -} - -/** - * If a field has no getter, it's not accessible as a property from Kotlin's perspective, - * but it still might have a setter lookalike. In this case, this "setter" should be just a regular function - * - * @return removed elements - */ -private fun removeNonAccessorsReturning( - propertyAccessors: MutableMap<PropertyDescriptor, DescriptorAccessorHolder> -): List<FunctionDescriptor> { - val nonAccessors = mutableListOf<FunctionDescriptor>() - propertyAccessors.entries.removeIf { (_, accessors) -> - if (accessors.getter == null && accessors.setter != null) { - nonAccessors.add(accessors.setter) - true - } else { - false - } - } - return nonAccessors -} - -private fun FunctionDescriptor.toPossiblePropertyNames(): List<String> { - val stringName = this.name.asString() - return when { - JvmAbi.isSetterName(stringName) -> propertyNamesBySetMethodName(this.name).map { it.asString() } - JvmAbi.isGetterName(stringName) -> propertyNamesByGetMethod(this) - else -> listOf() - } -} - -private fun propertyNamesByGetMethod(functionDescriptor: FunctionDescriptor): List<String> { - val stringName = functionDescriptor.name.asString() - // In java, the convention for boolean property accessors is as follows: - // - `private boolean active;` - // - `private boolean isActive();` - // - // Whereas in Kotlin, because there are no explicit accessors, the convention is - // - `val isActive: Boolean` - // - // This makes it difficult to guess the name of the accessor property in case of Java - val javaPropName = if (functionDescriptor is JavaMethodDescriptor && JvmAbi.startsWithIsPrefix(stringName)) { - val javaPropName = stringName.removePrefix("is").let { newName -> - newName.replaceFirst(newName[0], newName[0].toLowerCase()) - } - javaPropName - } else { - null - } - val kotlinPropName = propertyNameByGetMethodName(functionDescriptor.name)?.asString() - return listOfNotNull(javaPropName, kotlinPropName) -} - -private fun FunctionDescriptor.isAccessorFor(property: PropertyDescriptor): Boolean { - return (this.isGetterFor(property) || this.isSetterFor(property)) - && !property.visibility.isPublicAPI - && this.visibility.isPublicAPI -} - -private fun FunctionDescriptor.isGetterFor(property: PropertyDescriptor): Boolean { - return this.returnType == property.returnType - && this.valueParameters.isEmpty() -} - -private fun FunctionDescriptor.isSetterFor(property: PropertyDescriptor): Boolean { - return this.valueParameters.size == 1 - && this.valueParameters[0].type == property.returnType -} - diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt deleted file mode 100644 index 7a305bc1..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/ExternalClasslikesTranslator.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.model.DClasslike -import org.jetbrains.kotlin.descriptors.ClassDescriptor - -/** - * Service translating [ClassDescriptor]s of symbols defined outside of documented project to [DClasslike]s. - */ -internal fun interface ExternalClasslikesTranslator { - fun translateClassDescriptor(descriptor: ClassDescriptor, sourceSet: DokkaSourceSet): DClasslike -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt deleted file mode 100644 index 7c304e39..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/KdocMarkdownParser.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.analysis.markdown.jb.MarkdownParser -import org.jetbrains.dokka.analysis.markdown.jb.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<KDocTag> = - kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { - getAllKDocTags(it) - } diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt deleted file mode 100644 index cff24590..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/SyntheticDescriptorDocumentationProvider.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -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.jb.MarkdownParser -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.DescriptorUtils - -private const val ENUM_ENTRIES_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumEntries.kt.template" -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 kDocFinder: KDocFinder, - private val sourceSet: DokkaConfiguration.DokkaSourceSet -) { - fun isDocumented(descriptor: DeclarationDescriptor): Boolean { - return when(descriptor) { - is PropertyDescriptor -> descriptor.isEnumEntries() - is FunctionDescriptor -> { - DescriptorFactory.isEnumValuesMethod(descriptor) || DescriptorFactory.isEnumValueOfMethod(descriptor) - } - else -> false - } - } - - private fun PropertyDescriptor.isEnumEntries(): Boolean { - return this.name == StandardNames.ENUM_ENTRIES - && this.kind == CallableMemberDescriptor.Kind.SYNTHESIZED - && DescriptorUtils.isEnumClass(this.containingDeclaration) - } - - fun getDocumentation(descriptor: DeclarationDescriptor): DocumentationNode? { - return when(descriptor) { - is PropertyDescriptor -> descriptor.getDocumentation() - is FunctionDescriptor -> descriptor.getDocumentation() - else -> null - } - } - - private fun PropertyDescriptor.getDocumentation(): DocumentationNode? { - return when { - this.isEnumEntries() -> loadTemplate(this, ENUM_ENTRIES_TEMPLATE_PATH) - else -> null - } - } - - private fun FunctionDescriptor.getDocumentation(): DocumentationNode? { - return when { - DescriptorFactory.isEnumValuesMethod(this) -> loadTemplate(this, ENUM_VALUES_TEMPLATE_PATH) - DescriptorFactory.isEnumValueOfMethod(this) -> loadTemplate(this, ENUM_VALUEOF_TEMPLATE_PATH) - else -> null - } - } - - private fun loadTemplate(descriptor: DeclarationDescriptor, filePath: String): DocumentationNode? { - val kdoc = loadContent(filePath) ?: return null - val parser = MarkdownParser({ link -> resolveLink(descriptor, link)}, filePath) - return parser.parse(kdoc) - } - - private fun loadContent(filePath: String): String? = javaClass.getResource(filePath)?.readText() - - private fun resolveLink(descriptor: DeclarationDescriptor, link: String): DRI? = - kDocFinder.resolveKDocLink( - fromDescriptor = descriptor, - qualifiedName = link, - sourceSet = sourceSet - ).firstOrNull()?.let { DRI.from(it) } -} diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt deleted file mode 100644 index 6944ac1d..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/annotationsValue.kt +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -internal fun unquotedValue(value: String): String = value.removeSurrounding("\"") diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt deleted file mode 100644 index e484f37a..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/translator/isException.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.translator - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.AncestryNode -import org.jetbrains.dokka.model.TypeConstructor - -internal fun AncestryNode.typeConstructorsBeingExceptions(): List<TypeConstructor> { - fun traverseSupertypes(ancestry: AncestryNode): List<TypeConstructor> = - listOf(ancestry.typeConstructor) + (ancestry.superclass?.let(::traverseSupertypes) ?: emptyList()) - - return superclass?.let(::traverseSupertypes)?.filter { type -> type.dri.isDirectlyAnException() } ?: emptyList() -} - -internal fun DRI.isDirectlyAnException(): Boolean = - toString().let { stringed -> - stringed == "kotlin/Exception///PointingToDeclaration/" || - stringed == "java.lang/Exception///PointingToDeclaration/" - } diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/subprojects/analysis-kotlin-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin deleted file mode 100644 index 0d7ee9f6..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. -# - -org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin diff --git a/subprojects/analysis-kotlin-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt b/subprojects/analysis-kotlin-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt deleted file mode 100644 index 76be1384..00000000 --- a/subprojects/analysis-kotlin-descriptors/compiler/src/test/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ParseModuleAndPackageDocumentationFragmentsTest.kt +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors - - -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.moduledocs.* -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.jb.MARKDOWN_ELEMENT_FILE_NAME -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.utilities.DokkaLogger -import org.junit.jupiter.api.io.TempDir -import java.nio.file.Path -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith -import kotlin.test.assertTrue - -class ParseModuleAndPackageDocumentationFragmentsTest { - - private fun testBasicExample(lineSeperator: String = "\n") { - val source = source( - """ - # Module kotlin-demo - Module description - - # Package org.jetbrains.kotlin.demo - Package demo description - ## Level 2 heading - Heading 2\r\n - - # Package org.jetbrains.kotlin.demo2 - Package demo2 description - """.trimIndent().replace("\n", lineSeperator) - ) - val fragments = parseModuleAndPackageDocumentationFragments(source) - - assertEquals( - listOf( - ModuleAndPackageDocumentationFragment( - classifier = Module, - name = "kotlin-demo", - documentation = "Module description", - source = source - ), - ModuleAndPackageDocumentationFragment( - classifier = Package, - name = "org.jetbrains.kotlin.demo", - documentation = "Package demo description${lineSeperator}## Level 2 heading${lineSeperator}Heading 2\\r\\n", - source = source - ), - ModuleAndPackageDocumentationFragment( - classifier = Package, - name = "org.jetbrains.kotlin.demo2", - documentation = "Package demo2 description", - source = source - ) - ), - fragments - ) - } - - @Test - fun `basic example`() { - testBasicExample() - } - - @Test - fun `CRLF line seperators`() { - testBasicExample("\r\n") - } - - @Test - fun `no module name specified fails`() { - val exception = assertFailsWith<IllegalModuleAndPackageDocumentation> { - parseModuleAndPackageDocumentationFragments( - source( - """ - # Module - No module name given - """.trimIndent() - ) - ) - } - - assertTrue( - "Missing Module name" in exception.message.orEmpty(), - "Expected 'Missing Module name' in error message" - ) - } - - @Test - fun `no package name specified does not fail`() { - val source = source( - """ - # Package - This is a root package - """.trimIndent() - ) - val fragments = parseModuleAndPackageDocumentationFragments(source) - assertEquals(1, fragments.size, "Expected a single package fragment") - - assertEquals( - ModuleAndPackageDocumentationFragment( - name = "", - classifier = Package, - documentation = "This is a root package", - source = source - ), - fragments.single() - ) - } - - @Test - fun `white space in module name is supported`() { - val fragment = parseModuleAndPackageDocumentationFragments( - source( - """ - # Module My Module - Documentation for my module - """.trimIndent() - ) - ) - - assertEquals( - Module, fragment.single().classifier, - "Expected module being parsec" - ) - - assertEquals( - "My Module", fragment.single().name, - "Expected module name with white spaces being parsed" - ) - - assertEquals( - "Documentation for my module", fragment.single().documentation, - "Expected documentation being available" - ) - } - - @Test - fun `white space in package name fails`() { - val exception = assertFailsWith<IllegalModuleAndPackageDocumentation> { - parseModuleAndPackageDocumentationFragments( - source( - """ - # Package my package - """.trimIndent() - ) - ) - } - - assertTrue( - "Package my package" in exception.message.orEmpty(), - "Expected problematic statement in error message" - ) - } - - @Test - fun `multiple whitespaces are supported in first line`() { - val source = source( - """ - # Module my-module - My Module - # Package com.my.package - My Package - """.trimIndent() - ) - val fragments = parseModuleAndPackageDocumentationFragments(source) - - assertEquals( - listOf( - ModuleAndPackageDocumentationFragment( - classifier = Module, - name = "my-module", - documentation = "My Module", - source = source - ), - ModuleAndPackageDocumentationFragment( - classifier = Package, - name = "com.my.package", - documentation = "My Package", - source = source - ) - ), - fragments - ) - } - - @Test - fun `parse from file`(@TempDir temporaryFolder: Path) { - val file = temporaryFolder.resolve("other.md").toFile() - file.writeText( - """ - # Module MyModule - D1 - # Package com.sample - D2 - """.trimIndent() - ) - - assertEquals( - listOf( - ModuleAndPackageDocumentationFragment( - classifier = Module, - name = "MyModule", - documentation = "D1", - source = ModuleAndPackageDocumentationFile(file) - ), - ModuleAndPackageDocumentationFragment( - classifier = Package, - name = "com.sample", - documentation = "D2", - source = ModuleAndPackageDocumentationFile(file) - ) - ), - parseModuleAndPackageDocumentationFragments(file) - ) - } - - @Test - fun `at in code block is supported`() { - val fragment = parseModuleAndPackageDocumentationFragments( - source( - """ - # Module My Module - ``` - @Smth - ``` - @author Smb - """.trimIndent() - ) - ) - - assertEquals( - "```\n" + - "@Smth\n" + - "```\n" + - "@author Smb", fragment.single().documentation, - "Expected documentation being available" - ) - - val parsingContext = ModuleAndPackageDocumentationParsingContext(object : DokkaLogger { - override var warningsCount: Int = 0 - override var errorsCount: Int = 0 - override fun debug(message: String) {} - override fun info(message: String) {} - override fun progress(message: String) {} - override fun warn(message: String) {} - override fun error(message: String) {} - }) - val parsedFragment = parseModuleAndPackageDocumentation(parsingContext, fragment.single()) - val expectedDocumentationNode = DocumentationNode( - listOf( - Description( - CustomDocTag( - listOf( - CodeBlock( - listOf( - Text("@Smth") - ) - ) - ), name = MARKDOWN_ELEMENT_FILE_NAME - ) - ), - Author( - CustomDocTag( - listOf( - P(listOf(Text("Smb"))) - ), name = MARKDOWN_ELEMENT_FILE_NAME - ) - ) - ) - ) - assertEquals( - expectedDocumentationNode, parsedFragment.documentation - ) - } - - private fun source(documentation: String): ModuleAndPackageDocumentationSource = - object : ModuleAndPackageDocumentationSource() { - override val sourceDescription: String = "inline test" - override val documentation: String = documentation - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/README.md b/subprojects/analysis-kotlin-descriptors/ide/README.md deleted file mode 100644 index 14ed5baa..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Descriptors: IDE - -An internal module that encapsulates external IDE (`org.jetbrains.kotlin:idea`) dependencies. - -IDE artifacts are reused for things that are not possible to do with the Kotlin compiler API, such -as KDoc or KLib parsing/processing, because Dokka is very similar to an IDE when it comes to analyzing -source code and docs. - -Exists primarily to make sure that unreliable and coupled external dependencies are somewhat abstracted away, -otherwise everything gets tangled together and breaking changes in such dependencies become very -difficult to resolve. diff --git a/subprojects/analysis-kotlin-descriptors/ide/api/ide.api b/subprojects/analysis-kotlin-descriptors/ide/api/ide.api deleted file mode 100644 index a59658a3..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/api/ide.api +++ /dev/null @@ -1,4 +0,0 @@ -public final class org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { - public fun <init> ()V -} - diff --git a/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts b/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts deleted file mode 100644 index 9783a71c..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -plugins { - id("org.jetbrains.conventions.kotlin-jvm") -} - -dependencies { - compileOnly(projects.core) - compileOnly(projects.subprojects.analysisKotlinApi) - - implementation(projects.subprojects.analysisKotlinDescriptors.compiler) - - // TODO [beresnev] get rid of it - compileOnly(libs.kotlinx.coroutines.core) -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt deleted file mode 100644 index 2a299009..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/CoreKotlinCacheService.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.intellij.psi.PsiFile -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.caches.resolve.PlatformAnalysisSettings -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache - - -internal class CoreKotlinCacheService(private val resolutionFacade: DokkaResolutionFacade) : KotlinCacheService { - override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacade(element: KtElement): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeByFile( - file: PsiFile, - platform: TargetPlatform - ): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeByModuleInfo( - moduleInfo: ModuleInfo, - settings: PlatformAnalysisSettings - ): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeByModuleInfo( - moduleInfo: ModuleInfo, - platform: TargetPlatform - ): ResolutionFacade { - return resolutionFacade - } - - override fun getResolutionFacadeWithForcedPlatform( - elements: List<KtElement>, - platform: TargetPlatform - ): ResolutionFacade { - return resolutionFacade - } - - override fun getSuppressionCache(): KotlinSuppressCache { - throw UnsupportedOperationException() - } - -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt deleted file mode 100644 index 1ded0495..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/DokkaResolutionFacade.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -@file:OptIn(FrontendInternals::class) - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.google.common.collect.ImmutableMap -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ResolverForModule -import org.jetbrains.kotlin.analyzer.ResolverForProject -import org.jetbrains.kotlin.container.getService -import org.jetbrains.kotlin.container.tryGetService -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.idea.FrontendInternals -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.resolve.lazy.ResolveSession -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice -import org.jetbrains.kotlin.util.slicedMap.WritableSlice - -internal class DokkaResolutionFacade( - override val project: Project, - override val moduleDescriptor: ModuleDescriptor, - val resolverForModule: ResolverForModule -) : ResolutionFacade { - override fun analyzeWithAllCompilerChecks( - elements: Collection<KtElement>, - callback: DiagnosticSink.DiagnosticsCallback? - ): AnalysisResult { - throw UnsupportedOperationException() - } - - @OptIn(FrontendInternals::class) - override fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T? { - return resolverForModule.componentProvider.tryGetService(serviceClass) - } - - override fun resolveToDescriptor( - declaration: KtDeclaration, - bodyResolveMode: BodyResolveMode - ): DeclarationDescriptor { - return resolveSession.resolveToDescriptor(declaration) - } - - override fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext { - throw UnsupportedOperationException() - } - - val resolveSession: ResolveSession get() = getFrontendService(ResolveSession::class.java) - - override fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode): BindingContext { - if (element is KtDeclaration) { - val descriptor = resolveToDescriptor(element) - return object : BindingContext { - override fun <K : Any?, V : Any?> getKeys(p0: WritableSlice<K, V>?): Collection<K> { - throw UnsupportedOperationException() - } - - override fun getType(p0: KtExpression): KotlinType? { - throw UnsupportedOperationException() - } - - override fun <K : Any?, V : Any?> get(slice: ReadOnlySlice<K, V>?, key: K): V? { - if (key != element) { - throw UnsupportedOperationException() - } - @Suppress("UNCHECKED_CAST") - return when { - slice == BindingContext.DECLARATION_TO_DESCRIPTOR -> descriptor as V - slice == BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER && (element as KtParameter).hasValOrVar() -> descriptor as V - else -> null - } - } - - override fun getDiagnostics(): Diagnostics { - throw UnsupportedOperationException() - } - - override fun addOwnDataTo(p0: BindingTrace, p1: Boolean) { - throw UnsupportedOperationException() - } - - override fun <K : Any?, V : Any?> getSliceContents(p0: ReadOnlySlice<K, V>): ImmutableMap<K, V> { - throw UnsupportedOperationException() - } - - } - } - throw UnsupportedOperationException() - } - - override fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T { - throw UnsupportedOperationException() - } - - override fun <T : Any> getFrontendService(serviceClass: Class<T>): T { - return resolverForModule.componentProvider.getService(serviceClass) - } - - @Deprecated("DO NOT USE IT AS IT IS A ROOT CAUSE OF KTIJ-17649") - override fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T { - return resolverForModule.componentProvider.getService(serviceClass) - } - - override fun <T : Any> getIdeService(serviceClass: Class<T>): T { - throw UnsupportedOperationException() - } - - override fun getResolverForProject(): ResolverForProject<out ModuleInfo> { - throw UnsupportedOperationException() - } - -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt deleted file mode 100644 index 252fbd55..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeAnalysisContextCreator.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.intellij.mock.MockComponentManager -import com.intellij.mock.MockProject -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.AnalysisContextCreator -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment -import org.jetbrains.kotlin.analyzer.ResolverForModule -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.descriptors.ModuleDescriptor - -internal class IdeAnalysisContextCreator : 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) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt deleted file mode 100644 index e170b740..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorAnalysisPlugin.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.plugability.DokkaPluginApiPreview -import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement - -@InternalDokkaApi -public class IdeDescriptorAnalysisPlugin : DokkaPlugin() { - - internal val ideKdocFinder by extending { - plugin<CompilerDescriptorAnalysisPlugin>().kdocFinder providing ::IdePluginKDocFinder - } - - internal val ideDescriptorFinder by extending { - plugin<CompilerDescriptorAnalysisPlugin>().descriptorFinder providing { IdeDescriptorFinder() } - } - - internal val ideKlibService by extending { - plugin<CompilerDescriptorAnalysisPlugin>().klibService providing { IdeKLibService() } - } - - internal val ideApplicationHack by extending { - plugin<CompilerDescriptorAnalysisPlugin>().mockApplicationHack providing { IdeMockApplicationHack() } - } - - internal val ideAnalysisContextCreator by extending { - plugin<CompilerDescriptorAnalysisPlugin>().analysisContextCreator providing { IdeAnalysisContextCreator() } - } - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt deleted file mode 100644 index 7a1e04e4..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeDescriptorFinder.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.DescriptorFinder -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode - -internal class IdeDescriptorFinder : DescriptorFinder { - override fun KtDeclaration.findDescriptor(): DeclarationDescriptor? { - return if (this is KtParameter) this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) else this.resolveToDescriptorIfAny( - BodyResolveMode.FULL - ) - } - -} - - diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt deleted file mode 100644 index e1c0eb31..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeKLibService.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KLibService -import org.jetbrains.kotlin.library.metadata.KlibMetadataModuleDescriptorFactory -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.idea.klib.CachingIdeKlibMetadataLoader -import org.jetbrains.kotlin.idea.klib.compatibilityInfo -import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration -import org.jetbrains.kotlin.storage.StorageManager - -internal class IdeKLibService : 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.compatibilityInfo.isCompatible - } -} - -internal fun KotlinLibrary.createKlibPackageFragmentProvider( - storageManager: StorageManager, - metadataModuleDescriptorFactory: KlibMetadataModuleDescriptorFactory, - languageVersionSettings: LanguageVersionSettings, - moduleDescriptor: ModuleDescriptor, - lookupTracker: LookupTracker -): PackageFragmentProvider? { - if (!compatibilityInfo.isCompatible) return null - - val packageFragmentNames = CachingIdeKlibMetadataLoader.loadModuleHeader(this).packageFragmentNameList - - return metadataModuleDescriptorFactory.createPackageFragmentProvider( - library = this, - packageAccessHandler = CachingIdeKlibMetadataLoader, - packageFragmentNames = packageFragmentNames, - storageManager = storageManager, - moduleDescriptor = moduleDescriptor, - configuration = CompilerDeserializationConfiguration(languageVersionSettings), - compositePackageFragmentAddend = null, - lookupTracker = lookupTracker - ) -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt deleted file mode 100644 index 2bc83504..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdeMockApplicationHack.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.intellij.mock.MockApplication -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.MockApplicationHack -import org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache - -internal class IdeMockApplicationHack : MockApplicationHack { - override fun hack(mockApplication: MockApplication) { - if (mockApplication.getService(KlibLoadingMetadataCache::class.java) == null) - mockApplication.registerService(KlibLoadingMetadataCache::class.java, KlibLoadingMetadataCache()) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt deleted file mode 100644 index 13119602..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/IdePluginKDocFinder.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.CompilerDescriptorAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.KDocFinder -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils - -internal class IdePluginKDocFinder( - private val context: DokkaContext -) : KDocFinder { - - override fun KtElement.findKDoc(): KDocTag? { - return this.findKDoc { DescriptorToSourceUtils.descriptorToDeclaration(it) }?.contentTag - } - - override fun DeclarationDescriptor.find(descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement?): KDocTag? { - return this.findKDoc(descriptorToPsi)?.contentTag - } - - override fun resolveKDocLink( - fromDescriptor: DeclarationDescriptor, - qualifiedName: String, - sourceSet: DokkaConfiguration.DokkaSourceSet, - emptyBindingContext: Boolean - ): Collection<DeclarationDescriptor> { - val facadeAnalysisContext = context - .plugin<CompilerDescriptorAnalysisPlugin>() - .querySingle { kotlinAnalysis }[sourceSet] as ResolutionFacadeAnalysisContext - - return org.jetbrains.kotlin.idea.kdoc.resolveKDocLink( - context = if (emptyBindingContext) BindingContext.EMPTY else facadeAnalysisContext.resolveSession.bindingContext, - resolutionFacade = facadeAnalysisContext.facade, - fromDescriptor = fromDescriptor, - fromSubjectOfTag = null, - qualifiedName = qualifiedName.split('.'), - contextElement = fromDescriptor.findPsi() - ) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt deleted file mode 100644 index d70aeb99..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/ide/ResolutionFacadeAnalysisContext.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.descriptors.ide - -import com.intellij.openapi.project.Project -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisContext -import org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.configuration.AnalysisEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.resolve.lazy.ResolveSession - -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() - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt deleted file mode 100644 index 0f1b3ccf..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/KotlinCacheService.kt +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.caches.resolve - -import com.intellij.openapi.components.ComponentManager -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFile -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache - -internal interface KotlinCacheService { - companion object { - inline fun <reified T : Any> ComponentManager.service(): T { - val serviceClass = T::class.java - return getService(serviceClass) - ?: error("Cannot find service ${serviceClass.name} in $this (classloader=${serviceClass.classLoader}") - } - - fun getInstance(project: Project): KotlinCacheService = project.service() - } - - /** - * Provides resolution facade for [elements], guaranteeing that the resolution will be seen from the [platform]-perspective. - * - * This allows to get resolution for common sources in MPP from the perspective of given platform (with expects substituted to actuals, - * declarations resolved from platform-specific artifacts, ModuleDescriptors will contain only platform dependencies, etc.) - * - * It is equivalent to usual [getResolutionFacade]-overloads if platform(s) of module(s) containing [elements] are equal to [platform] - * - * Doesn't support scripts or any other 'special' files. - */ - fun getResolutionFacadeWithForcedPlatform(elements: List<KtElement>, platform: TargetPlatform): ResolutionFacade - - fun getResolutionFacade(element: KtElement): ResolutionFacade - fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade - fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade? - - fun getSuppressionCache(): KotlinSuppressCache - fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade? - - fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade? -}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt deleted file mode 100644 index f828580c..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/caches/resolve/PlatformAnalysisSettings.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.caches.resolve - -/** - * Regulates which sources should be analyzed together. - * - * There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning - * that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type): - * - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate - * facade for each platforms, sdk, builtIns settings and other stuff. - * This is the old and stable mode, which should be used by default. - * - * - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources - * together, in one facade. - * This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend. - * This mode is currently enabled only for HMPP projects - */ -internal interface PlatformAnalysisSettings
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt deleted file mode 100644 index 3d93093f..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/caches/resolve/ExtendedResolutionApi.kt +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - -package org.jetbrains.kotlin.idea.caches.resolve - -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException - - -internal fun KtElement.getResolutionFacade(): ResolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacade(this) - -/** - * This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent), - * and then takes the relevant descriptor from binding context. - * The exact set of declarations to resolve depends on bodyResolveMode - */ -internal fun KtDeclaration.resolveToDescriptorIfAny( - resolutionFacade: ResolutionFacade, - bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL -): DeclarationDescriptor? { - //TODO: BodyResolveMode.PARTIAL is not quite safe! - val context = safeAnalyze(resolutionFacade, bodyResolveMode) - return if (this is KtParameter && hasValOrVar()) { - context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this) - // It is incorrect to have `val/var` parameters outside the primary constructor (e.g., `fun foo(val x: Int)`) - // but we still want to try to resolve in such cases. - ?: context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) - } else { - context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) - } -} - -internal fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = - resolveToParameterDescriptorIfAny(getResolutionFacade(), bodyResolveMode) - -internal fun KtParameter.resolveToParameterDescriptorIfAny( - resolutionFacade: ResolutionFacade, - bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL -): ValueParameterDescriptor? { - val context = safeAnalyze(resolutionFacade, bodyResolveMode) - return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor -} - -internal fun KtDeclaration.resolveToDescriptorIfAny( - bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL -): DeclarationDescriptor? = - resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode) - -internal fun KtElement.analyze( - resolutionFacade: ResolutionFacade, - bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL -): BindingContext = resolutionFacade.analyze(this, bodyResolveMode) - -internal fun KtElement.safeAnalyze( - resolutionFacade: ResolutionFacade, - bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL -): BindingContext = try { - analyze(resolutionFacade, bodyResolveMode) -} catch (e: Exception) { - e.returnIfNoDescriptorForDeclarationException { BindingContext.EMPTY } -} - -internal inline fun <T> Exception.returnIfNoDescriptorForDeclarationException( - crossinline condition: (Boolean) -> Boolean = { v -> v }, - crossinline computable: () -> T -): T = - if (condition(this.isItNoDescriptorForDeclarationException)) { - computable() - } else { - throw this - } - -internal val Exception.isItNoDescriptorForDeclarationException: Boolean - get() = this is NoDescriptorForDeclarationException || (cause as? Exception)?.isItNoDescriptorForDeclarationException == true diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt deleted file mode 100644 index 1accf430..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/findKDoc.kt +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - -package org.jetbrains.kotlin.idea.kdoc - -import com.intellij.psi.PsiElement -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType -import org.jetbrains.kotlin.psi.psiUtil.getChildOfType -import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType -import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly - -internal data class KDocContent( - val contentTag: KDocTag, - val sections: List<KDocSection> -) - -internal fun DeclarationDescriptor.findKDoc( - descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { DescriptorToSourceUtils.descriptorToDeclaration(it) } -): KDocContent? { - if (this is DeclarationDescriptorWithSource) { - val psiDeclaration = descriptorToPsi(this)?.navigationElement - return (psiDeclaration as? KtElement)?.findKDoc(descriptorToPsi) - } - return null -} - -private typealias DescriptorToPsi = (DeclarationDescriptorWithSource) -> PsiElement? - -internal fun KtElement.findKDoc(descriptorToPsi: DescriptorToPsi): KDocContent? { - return findKDoc() - ?: this.lookupInheritedKDoc(descriptorToPsi) -} - -internal fun KtElement.findKDoc(): KDocContent? { - return this.lookupOwnedKDoc() - ?: this.lookupKDocInContainer() -} - -private fun KtElement.lookupOwnedKDoc(): KDocContent? { - // KDoc for primary constructor is located inside of its class KDoc - val psiDeclaration = when (this) { - is KtPrimaryConstructor -> getContainingClassOrObject() - else -> this - } - - if (psiDeclaration is KtDeclaration) { - val kdoc = psiDeclaration.docComment - if (kdoc != null) { - if (this is KtConstructor<*>) { - // ConstructorDescriptor resolves to the same JetDeclaration - val constructorSection = kdoc.findSectionByTag(KDocKnownTag.CONSTRUCTOR) - if (constructorSection != null) { - // if annotated with @constructor tag and the caret is on constructor definition, - // then show @constructor description as the main content, and additional sections - // that contain @param tags (if any), as the most relatable ones - // practical example: val foo = Fo<caret>o("argument") -- show @constructor and @param content - val paramSections = kdoc.findSectionsContainingTag(KDocKnownTag.PARAM) - return KDocContent(constructorSection, paramSections) - } - } - return KDocContent(kdoc.getDefaultSection(), kdoc.getAllSections()) - } - } - return null -} - -/** - * Looks for sections that have a deeply nested [tag], - * as opposed to [KDoc.findSectionByTag], which only looks among the top level - */ -private fun KDoc.findSectionsContainingTag(tag: KDocKnownTag): List<KDocSection> { - return getChildrenOfType<KDocSection>() - .filter { it.findTagByName(tag.name.toLowerCaseAsciiOnly()) != null } -} - -private fun KtElement.lookupKDocInContainer(): KDocContent? { - val subjectName = name - val containingDeclaration = - PsiTreeUtil.findFirstParent(this, true) { - it is KtDeclarationWithBody && it !is KtPrimaryConstructor - || it is KtClassOrObject - } - - val containerKDoc = containingDeclaration?.getChildOfType<KDoc>() - if (containerKDoc == null || subjectName == null) return null - val propertySection = containerKDoc.findSectionByTag(KDocKnownTag.PROPERTY, subjectName) - val paramTag = containerKDoc.findDescendantOfType<KDocTag> { it.knownTag == KDocKnownTag.PARAM && it.getSubjectName() == subjectName } - - val primaryContent = when { - // class Foo(val <caret>s: String) - this is KtParameter && this.isPropertyParameter() -> propertySection ?: paramTag - // fun some(<caret>f: String) || class Some<<caret>T: Base> || Foo(<caret>s = "argument") - this is KtParameter || this is KtTypeParameter -> paramTag - // if this property is declared separately (outside primary constructor), but it's for some reason - // annotated as @property in class's description, instead of having its own KDoc - this is KtProperty && containingDeclaration is KtClassOrObject -> propertySection - else -> null - } - return primaryContent?.let { - // makes little sense to include any other sections, since we found - // documentation for a very specific element, like a property/param - KDocContent(it, sections = emptyList()) - } -} - -private fun KtElement.lookupInheritedKDoc(descriptorToPsi: DescriptorToPsi): KDocContent? { - if (this is KtCallableDeclaration) { - val descriptor = this.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null - - for (baseDescriptor in descriptor.overriddenDescriptors) { - val baseKDoc = baseDescriptor.original.findKDoc(descriptorToPsi) - if (baseKDoc != null) { - return baseKDoc - } - } - } - return null -}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt deleted file mode 100644 index 7e4e0bb5..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/kdoc/resolveKDocLink.kt +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. - -package org.jetbrains.kotlin.idea.kdoc - -import com.intellij.openapi.components.ComponentManager -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.FrontendInternals -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.resolve.frontendService -import org.jetbrains.kotlin.idea.util.CallType -import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable -import org.jetbrains.kotlin.incremental.components.LookupLocation -import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtPsiFactory -import org.jetbrains.kotlin.psi.KtQualifiedExpression -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil -import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver -import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension -import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider -import org.jetbrains.kotlin.resolve.scopes.* -import org.jetbrains.kotlin.resolve.scopes.utils.* -import org.jetbrains.kotlin.resolve.source.PsiSourceElement -import org.jetbrains.kotlin.utils.Printer -import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addIfNotNull - -/** - * Returns `null` if the service cannot be found in [this] component manager, - * otherwise initializes a service if not yet initialized, and returns the service instance. - * @see ComponentManager.getService - */ -internal inline fun <reified T : Any> ComponentManager.serviceOrNull(): T? { - return getService(T::class.java) -} - -@OptIn(FrontendInternals::class) -internal fun ResolutionFacade.getFileResolutionScope(file: KtFile): LexicalScope { - return frontendService<FileScopeProvider>().getFileResolutionScope(file) -} - -internal fun resolveKDocLink( - context: BindingContext, - resolutionFacade: ResolutionFacade, - fromDescriptor: DeclarationDescriptor, - contextElement: PsiElement?, - fromSubjectOfTag: KDocTag?, - qualifiedName: List<String> -): Collection<DeclarationDescriptor> { - val tag = fromSubjectOfTag?.knownTag - if (tag == KDocKnownTag.PARAM) { - return resolveParamLink(fromDescriptor, qualifiedName) - } - val contextScope = getKDocLinkResolutionScope(resolutionFacade, fromDescriptor) - if (qualifiedName.size == 1) { - val localDescriptors = resolveLocal(qualifiedName.single(), contextScope, fromDescriptor) - if (localDescriptors.isNotEmpty()) { - return localDescriptors - } - } - - // [IdeKDocLinkResolutionService] is omitted - - return resolveDefaultKDocLink(context, resolutionFacade, contextElement, qualifiedName, contextScope) -} - -internal fun getParamDescriptors(fromDescriptor: DeclarationDescriptor): List<DeclarationDescriptor> { - // TODO resolve parameters of functions passed as parameters - when (fromDescriptor) { - is CallableDescriptor -> { - return fromDescriptor.valueParameters + fromDescriptor.typeParameters - } - - is ClassifierDescriptor -> { - val typeParams = fromDescriptor.typeConstructor.parameters - if (fromDescriptor is ClassDescriptor) { - val constructorDescriptor = fromDescriptor.unsubstitutedPrimaryConstructor - if (constructorDescriptor != null) { - return typeParams + constructorDescriptor.valueParameters - } - } - return typeParams - } - - else -> { - return emptyList() - } - } -} - -private fun resolveParamLink(fromDescriptor: DeclarationDescriptor, qualifiedName: List<String>): List<DeclarationDescriptor> { - val name = qualifiedName.singleOrNull() ?: return emptyList() - return getParamDescriptors(fromDescriptor).filter { it.name.asString() == name } -} - -private fun resolveLocal( - nameToResolve: String, - contextScope: LexicalScope, - fromDescriptor: DeclarationDescriptor -): List<DeclarationDescriptor> { - val shortName = Name.identifier(nameToResolve) - - val descriptorsByName = SmartList<DeclarationDescriptor>() - descriptorsByName.addIfNotNull(contextScope.findClassifier(shortName, NoLookupLocation.FROM_IDE)) - descriptorsByName.addIfNotNull(contextScope.findPackage(shortName)) - descriptorsByName.addAll(contextScope.collectFunctions(shortName, NoLookupLocation.FROM_IDE)) - descriptorsByName.addAll(contextScope.collectVariables(shortName, NoLookupLocation.FROM_IDE)) - - if (fromDescriptor is FunctionDescriptor && fromDescriptor.isExtension && shortName.asString() == "this") { - return listOfNotNull(fromDescriptor.extensionReceiverParameter) - } - - // Try to find a matching local descriptor (parameter or type parameter) first - val localDescriptors = descriptorsByName.filter { it.containingDeclaration == fromDescriptor } - if (localDescriptors.isNotEmpty()) return localDescriptors - - return descriptorsByName -} - -private fun resolveDefaultKDocLink( - context: BindingContext, - resolutionFacade: ResolutionFacade, - contextElement: PsiElement?, - qualifiedName: List<String>, - contextScope: LexicalScope -): Collection<DeclarationDescriptor> { - @OptIn(FrontendInternals::class) - val qualifiedExpressionResolver = resolutionFacade.getFrontendService(QualifiedExpressionResolver::class.java) - - val factory = KtPsiFactory(resolutionFacade.project) - // TODO escape identifiers - val codeFragment = factory.createExpressionCodeFragment(qualifiedName.joinToString("."), contextElement) - val qualifiedExpression = - codeFragment.findElementAt(codeFragment.textLength - 1)?.getStrictParentOfType<KtQualifiedExpression>() ?: return emptyList() - val (descriptor, memberName) = qualifiedExpressionResolver.resolveClassOrPackageInQualifiedExpression( - qualifiedExpression, - contextScope, - context - ) - if (descriptor == null) return emptyList() - if (memberName != null) { - val memberScope = getKDocLinkMemberScope(descriptor, contextScope) - return memberScope.getContributedFunctions(memberName, NoLookupLocation.FROM_IDE) + - memberScope.getContributedVariables(memberName, NoLookupLocation.FROM_IDE) + - listOfNotNull(memberScope.getContributedClassifier(memberName, NoLookupLocation.FROM_IDE)) - } - return listOf(descriptor) -} - -private fun getPackageInnerScope(descriptor: PackageFragmentDescriptor): MemberScope { - return descriptor.containingDeclaration.getPackage(descriptor.fqName).memberScope -} - -private fun getClassInnerScope(outerScope: LexicalScope, descriptor: ClassDescriptor): LexicalScope { - - val headerScope = LexicalScopeImpl( - outerScope, descriptor, false, descriptor.thisAsReceiverParameter, - descriptor.contextReceivers, LexicalScopeKind.SYNTHETIC - ) { - descriptor.declaredTypeParameters.forEach { addClassifierDescriptor(it) } - descriptor.constructors.forEach { addFunctionDescriptor(it) } - } - - return LexicalChainedScope.create( - headerScope, descriptor, false, null, emptyList(), LexicalScopeKind.SYNTHETIC, - descriptor.defaultType.memberScope, - descriptor.staticScope, - descriptor.companionObjectDescriptor?.defaultType?.memberScope - ) -} - -internal fun getKDocLinkResolutionScope(resolutionFacade: ResolutionFacade, contextDescriptor: DeclarationDescriptor): LexicalScope { - return when (contextDescriptor) { - is PackageFragmentDescriptor -> - LexicalScope.Base(getPackageInnerScope(contextDescriptor).memberScopeAsImportingScope(), contextDescriptor) - - is PackageViewDescriptor -> - LexicalScope.Base(contextDescriptor.memberScope.memberScopeAsImportingScope(), contextDescriptor) - - is ClassDescriptor -> - getClassInnerScope(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor) - - is FunctionDescriptor -> FunctionDescriptorUtil.getFunctionInnerScope( - getOuterScope(contextDescriptor, resolutionFacade), - contextDescriptor, LocalRedeclarationChecker.DO_NOTHING - ) - - is PropertyDescriptor -> - ScopeUtils.makeScopeForPropertyHeader(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor) - - is DeclarationDescriptorNonRoot -> - getOuterScope(contextDescriptor, resolutionFacade) - - else -> throw IllegalArgumentException("Cannot find resolution scope for root $contextDescriptor") - } -} - -private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, resolutionFacade: ResolutionFacade): LexicalScope { - val parent = descriptor.containingDeclaration!! - if (parent is PackageFragmentDescriptor) { - val containingFile = (descriptor.source as? PsiSourceElement)?.psi?.containingFile as? KtFile ?: return LexicalScope.Base( - ImportingScope.Empty, - parent - ) - val kotlinCacheService = containingFile.project.serviceOrNull<KotlinCacheService>() - val facadeToUse = kotlinCacheService?.getResolutionFacade(containingFile) ?: resolutionFacade - return facadeToUse.getFileResolutionScope(containingFile) - } else { - return getKDocLinkResolutionScope(resolutionFacade, parent) - } -} - -internal fun getKDocLinkMemberScope(descriptor: DeclarationDescriptor, contextScope: LexicalScope): MemberScope { - return when (descriptor) { - is PackageFragmentDescriptor -> getPackageInnerScope(descriptor) - - is PackageViewDescriptor -> descriptor.memberScope - - is ClassDescriptor -> { - ChainedMemberScope.create( - "Member scope for KDoc resolve", listOfNotNull( - descriptor.unsubstitutedMemberScope, - descriptor.staticScope, - descriptor.companionObjectDescriptor?.unsubstitutedMemberScope, - ExtensionsScope(descriptor, contextScope) - ) - ) - } - - else -> MemberScope.Empty - } -} - -private class ExtensionsScope( - private val receiverClass: ClassDescriptor, - private val contextScope: LexicalScope -) : MemberScope { - private val receiverTypes = listOf(receiverClass.defaultType) - - override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> { - return contextScope.collectFunctions(name, location).flatMap { - if (it is SimpleFunctionDescriptor && it.isExtension) { - it.substituteExtensionIfCallable( - receiverTypes = receiverTypes, - callType = CallType.DOT, - ignoreTypeParameters = true, - ) - } else { - emptyList() - } - } - } - - override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> { - return contextScope.collectVariables(name, location).flatMap { - if (it is PropertyDescriptor && it.isExtension) { - it.substituteExtensionIfCallable( - receiverTypes = receiverTypes, - callType = CallType.DOT, - ignoreTypeParameters = true, - ) - } else { - emptyList() - } - } - } - - override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null - - override fun getContributedDescriptors( - kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean - ): Collection<DeclarationDescriptor> { - if (DescriptorKindExclude.Extensions in kindFilter.excludes) return emptyList() - return contextScope.collectDescriptorsFiltered( - kindFilter exclude DescriptorKindExclude.NonExtensions, - nameFilter, - changeNamesForAliased = true - ).flatMap { - if (it is CallableDescriptor && it.isExtension) { - it.substituteExtensionIfCallable( - receiverTypes = receiverTypes, - callType = CallType.DOT, - ignoreTypeParameters = true, - ) - } else { - emptyList() - } - } - } - - override fun getFunctionNames(): Set<Name> = - getContributedDescriptors(kindFilter = DescriptorKindFilter.FUNCTIONS).map { it.name }.toSet() - - override fun getVariableNames(): Set<Name> = - getContributedDescriptors(kindFilter = DescriptorKindFilter.VARIABLES).map { it.name }.toSet() - - override fun getClassifierNames() = null - - override fun printScopeStructure(p: Printer) { - p.println("Extensions for ${receiverClass.name} in:") - contextScope.printStructure(p) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt deleted file mode 100644 index 5c7ea8fb..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/CachingIdeKlibMetadataLoader.kt +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.kotlin.idea.klib - -import com.intellij.openapi.util.io.FileUtilRt -import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.openapi.vfs.VirtualFile -import org.jetbrains.annotations.Contract -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.impl.KotlinLibraryImpl -import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf -import org.jetbrains.kotlin.library.metadata.PackageAccessHandler -import org.jetbrains.kotlin.metadata.ProtoBuf -import org.jetbrains.kotlin.konan.file.File as KFile - - -@Contract("null -> null; !null -> !null") -internal fun toSystemIndependentName(path: String?): String? { - return if (path == null) null else FileUtilRt.toSystemIndependentName(path) -} - -internal object CachingIdeKlibMetadataLoader : PackageAccessHandler { - override fun loadModuleHeader(library: KotlinLibrary): KlibMetadataProtoBuf.Header { - val virtualFile = getVirtualFile(library, library.moduleHeaderFile) - return virtualFile?.let { cache.getCachedModuleHeader(virtualFile) } ?: KlibMetadataProtoBuf.Header.getDefaultInstance() - } - - override fun loadPackageFragment(library: KotlinLibrary, packageFqName: String, partName: String): ProtoBuf.PackageFragment { - val virtualFile = getVirtualFile(library, library.packageFragmentFile(packageFqName, partName)) - return virtualFile?.let { cache.getCachedPackageFragment(virtualFile) } ?: ProtoBuf.PackageFragment.getDefaultInstance() - } - - private fun getVirtualFile(library: KotlinLibrary, file: KFile): VirtualFile? = - if (library.isZipped) asJarFileSystemFile(library.libraryFile, file) else asLocalFile(file) - - private fun asJarFileSystemFile(jarFile: KFile, localFile: KFile): VirtualFile? { - val fullPath = jarFile.absolutePath + "!" + toSystemIndependentName(localFile.path) - return StandardFileSystems.jar().findFileByPath(fullPath) - } - - private fun asLocalFile(localFile: KFile): VirtualFile? { - val fullPath = localFile.absolutePath - return StandardFileSystems.local().findFileByPath(fullPath) - } - - private val cache - get() = KlibLoadingMetadataCache.getInstance() - - private val KotlinLibrary.moduleHeaderFile - get() = (this as KotlinLibraryImpl).metadata.access.layout.moduleHeaderFile - - private fun KotlinLibrary.packageFragmentFile(packageFqName: String, partName: String) = - (this as KotlinLibraryImpl).metadata.access.layout.packageFragmentFile(packageFqName, partName) - - private val KotlinLibrary.isZipped - get() = (this as KotlinLibraryImpl).base.access.layout.isZipped -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt deleted file mode 100644 index 4923534d..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibCompatibilityInfo.kt +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -@file:JvmName("KlibCompatibilityInfoUtils") - -package org.jetbrains.kotlin.idea.klib - - -import org.jetbrains.kotlin.library.* -import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion -import org.jetbrains.kotlin.library.metadata.metadataVersion -import java.io.IOException - -/** - * Whether a certain KLIB is compatible for the purposes of IDE: indexation, resolve, etc. - */ -internal sealed class KlibCompatibilityInfo(val isCompatible: Boolean) { - object Compatible : KlibCompatibilityInfo(true) - object Pre14Layout : KlibCompatibilityInfo(false) - class IncompatibleMetadata(val isOlder: Boolean) : KlibCompatibilityInfo(false) -} - - -internal fun <T> KotlinLibrary.safeRead(defaultValue: T, action: KotlinLibrary.() -> T) = try { - action() -} catch (_: IOException) { - defaultValue -} -internal val KotlinLibrary.compatibilityInfo: KlibCompatibilityInfo - get() { - val hasPre14Manifest = safeRead(false) { has_pre_1_4_manifest } - if (hasPre14Manifest) - return KlibCompatibilityInfo.Pre14Layout - - val metadataVersion = safeRead(null) { this.metadataVersion } - @Suppress("DEPRECATION") - return when { - metadataVersion == null -> { - // Too old KLIB format, even doesn't have metadata version - KlibCompatibilityInfo.IncompatibleMetadata(true) - } - - !metadataVersion.isCompatible() -> { - val isOlder = metadataVersion.isAtLeast(KlibMetadataVersion.INSTANCE) - KlibCompatibilityInfo.IncompatibleMetadata(!isOlder) - } - - else -> KlibCompatibilityInfo.Compatible - } - } diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt deleted file mode 100644 index 55c615f6..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.klib - -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.util.containers.ContainerUtil -import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME -import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION -import org.jetbrains.kotlin.library.KLIB_MODULE_METADATA_FILE_NAME -import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf -import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion -import org.jetbrains.kotlin.library.metadata.parseModuleHeader -import org.jetbrains.kotlin.library.metadata.parsePackageFragment -import org.jetbrains.kotlin.library.readKonanLibraryVersioning -import org.jetbrains.kotlin.metadata.ProtoBuf -import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion -import java.io.IOException -import java.util.* - -internal class KlibLoadingMetadataCache { - // Use special CacheKey class instead of VirtualFile for cache keys. Certain types of VirtualFiles (for example, obtained from JarFileSystem) - // do not compare path (url) and modification stamp in equals() method. - private data class CacheKey( - val url: String, - val modificationStamp: Long - ) { - constructor(virtualFile: VirtualFile) : this(virtualFile.url, virtualFile.modificationStamp) - } - - // ConcurrentWeakValueHashMap does not allow null values. - private class CacheValue<T : Any>(val value: T?) - - private val packageFragmentCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<ProtoBuf.PackageFragment>>() - private val moduleHeaderCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataProtoBuf.Header>>() - private val libraryMetadataVersionCache = ContainerUtil.createConcurrentWeakValueMap<CacheKey, CacheValue<KlibMetadataVersion>>() - - fun getCachedPackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { - check(packageFragmentFile.extension == KLIB_METADATA_FILE_EXTENSION) { - "Not a package metadata file: $packageFragmentFile" - } - - return packageFragmentCache.computeIfAbsent( - CacheKey(packageFragmentFile) - ) { - CacheValue(computePackageFragment(packageFragmentFile)) - }.value - } - - fun getCachedModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { - check(moduleHeaderFile.name == KLIB_MODULE_METADATA_FILE_NAME) { - "Not a module header file: $moduleHeaderFile" - } - - return moduleHeaderCache.computeIfAbsent( - CacheKey(moduleHeaderFile) - ) { - CacheValue(computeModuleHeader(moduleHeaderFile)) - }.value - } - - private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean { - val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return false - - val metadataVersion = libraryMetadataVersionCache.computeIfAbsent( - CacheKey(manifestFile) - ) { - CacheValue(computeLibraryMetadataVersion(manifestFile)) - }.value ?: return false - - @Suppress("DEPRECATION") - return metadataVersion.isCompatible() - } - - private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { - if (!isMetadataCompatible(packageFragmentFile.parent.parent.parent)) - return null - - return try { - parsePackageFragment(packageFragmentFile.contentsToByteArray(false)) - } catch (_: IOException) { - null - } - } - - private fun computeModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { - if (!isMetadataCompatible(moduleHeaderFile.parent.parent)) - return null - - return try { - parseModuleHeader(moduleHeaderFile.contentsToByteArray(false)) - } catch (_: IOException) { - null - } - } - - private fun computeLibraryMetadataVersion(manifestFile: VirtualFile): KlibMetadataVersion? = try { - val versioning = Properties().apply { manifestFile.inputStream.use { load(it) } }.readKonanLibraryVersioning() - versioning.metadataVersion?.let(BinaryVersion.Companion::parseVersionArray)?.let(::KlibMetadataVersion) - } catch (_: IOException) { - // ignore and cache null value - null - } catch (_: IllegalArgumentException) { - // ignore and cache null value - null - } - - companion object { - @JvmStatic - fun getInstance(): KlibLoadingMetadataCache = - ApplicationManager.getApplication().getService(KlibLoadingMetadataCache::class.java) - } - -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt deleted file mode 100644 index c4adb2e3..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.idea.resolve - -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ResolverForProject -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.idea.FrontendInternals -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode - -internal interface ResolutionFacade { - val project: Project - - fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext - fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext - - fun analyzeWithAllCompilerChecks(element: KtElement, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult - = analyzeWithAllCompilerChecks(listOf(element), callback) - - fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult - - fun fetchWithAllCompilerChecks(element: KtElement): AnalysisResult? = null - - fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor - - val moduleDescriptor: ModuleDescriptor - - // get service for the module this resolution was created for - @FrontendInternals - fun <T : Any> getFrontendService(serviceClass: Class<T>): T - - fun <T : Any> getIdeService(serviceClass: Class<T>): T - - // get service for the module defined by PsiElement/ModuleDescriptor passed as parameter - @FrontendInternals - fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T - - @FrontendInternals - fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T? - - @Deprecated("DO NOT USE IT AS IT IS A ROOT CAUSE OF KTIJ-17649") - @FrontendInternals - fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T - - fun getResolverForProject(): ResolverForProject<out ModuleInfo> -} - -@FrontendInternals -internal inline fun <reified T : Any> ResolutionFacade.frontendService(): T = this.getFrontendService(T::class.java) - -internal inline fun <reified T : Any> ResolutionFacade.ideService(): T = this.getIdeService(T::class.java) diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt deleted file mode 100644 index 6d3077e2..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/CallType.kt +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package org.jetbrains.kotlin.idea.util - -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter - - -@Suppress("ClassName") -internal sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: DescriptorKindFilter) { - object UNKNOWN : CallType<Nothing?>(DescriptorKindFilter.ALL) - - object DEFAULT : CallType<Nothing?>(DescriptorKindFilter.ALL) - - object DOT : CallType<KtExpression>(DescriptorKindFilter.ALL) - - object SAFE : CallType<KtExpression>(DescriptorKindFilter.ALL) - - object SUPER_MEMBERS : CallType<KtSuperExpression>( - DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude - ) - - object INFIX : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude) - - object OPERATOR : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude) - - class CallableReference(settings: LanguageVersionSettings) : - CallType<KtExpression?>(DescriptorKindFilter.CALLABLES exclude LocalsAndSyntheticExclude(settings)) { - override fun equals(other: Any?): Boolean = other is CallableReference - override fun hashCode(): Int = javaClass.hashCode() - } - - object IMPORT_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.ALL) - - object PACKAGE_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.PACKAGES) - - object TYPE : CallType<KtExpression?>( - DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) - exclude DescriptorKindExclude.EnumEntry - ) - - object DELEGATE : CallType<KtExpression?>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude) - - object ANNOTATION : CallType<KtExpression?>( - DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) - exclude NonAnnotationClassifierExclude - ) - - private object NonInfixExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor) = - !(descriptor is SimpleFunctionDescriptor && descriptor.isInfix) - - override val fullyExcludedDescriptorKinds: Int - get() = 0 - } - - private object NonOperatorExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor) = - !(descriptor is SimpleFunctionDescriptor && descriptor.isOperator) - - override val fullyExcludedDescriptorKinds: Int - get() = 0 - } - - private class LocalsAndSyntheticExclude(private val settings: LanguageVersionSettings) : DescriptorKindExclude() { - // Currently, Kotlin doesn't support references to local variables - // References to Java synthetic properties are supported only since Kotlin 1.9 - override fun excludes(descriptor: DeclarationDescriptor): Boolean = - descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED && - !settings.supportsFeature(LanguageFeature.ReferencesToSyntheticJavaProperties) - - override val fullyExcludedDescriptorKinds: Int - get() = 0 - } - - private object NonAnnotationClassifierExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor): Boolean { - if (descriptor !is ClassifierDescriptor) return false - return descriptor !is ClassDescriptor || descriptor.kind != ClassKind.ANNOTATION_CLASS - } - - override val fullyExcludedDescriptorKinds: Int get() = 0 - } - - private object AbstractMembersExclude : DescriptorKindExclude() { - override fun excludes(descriptor: DeclarationDescriptor) = - descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT - - override val fullyExcludedDescriptorKinds: Int - get() = 0 - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt deleted file mode 100644 index b8a1ae56..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/ExtensionsUtils.kt +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -@file:JvmName("ExtensionUtils") - -package org.jetbrains.kotlin.idea.util - -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeSubstitutor -import org.jetbrains.kotlin.types.typeUtil.TypeNullability -import org.jetbrains.kotlin.types.typeUtil.makeNotNullable -import org.jetbrains.kotlin.types.typeUtil.nullability - - -internal fun <TCallable : CallableDescriptor> TCallable.substituteExtensionIfCallable( - receiverTypes: Collection<KotlinType>, - callType: CallType<*>, - ignoreTypeParameters: Boolean = false, -): Collection<TCallable> { - if (!callType.descriptorKindFilter.accepts(this)) return listOf() - - var types = receiverTypes.asSequence() - if (callType == CallType.SAFE) { - types = types.map { it.makeNotNullable() } - } - - val extensionReceiverType = fuzzyExtensionReceiverType()!! - val substitutors = types.mapNotNull { - // NOTE: this creates a fuzzy type for `it` without type parameters - var substitutor = extensionReceiverType.checkIsSuperTypeOf(it) - - // If enabled, we can ignore type parameters in the receiver type, and only check whether the constructors match - if (ignoreTypeParameters && substitutor == null && it.constructor == extensionReceiverType.type.constructor) { - substitutor = TypeSubstitutor.EMPTY - } - - // check if we may fail due to receiver expression being nullable - if (substitutor == null && it.nullability() == TypeNullability.NULLABLE && extensionReceiverType.nullability() == TypeNullability.NOT_NULL) { - substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable()) - } - substitutor - } - - return if (typeParameters.isEmpty()) { // optimization for non-generic callables - if (substitutors.any()) listOf(this) else listOf() - } else { - substitutors - .mapNotNull { @Suppress("UNCHECKED_CAST") (substitute(it) as TCallable?) } - .toList() - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt deleted file mode 100644 index de0895e6..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/idea/util/FuzzyTypeUtils.kt +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -@file:JvmName("FuzzyTypeUtils") -package org.jetbrains.kotlin.idea.util - -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.resolve.calls.inference.CallHandle -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl -import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind -import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.types.error.ErrorUtils -import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker -import org.jetbrains.kotlin.types.typeUtil.* -import java.util.* - -internal fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters) - -internal fun FuzzyType.nullability() = type.nullability() - -internal fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters) - -internal class FuzzyType(val type: KotlinType, freeParameters: Collection<TypeParameterDescriptor>) { - val freeParameters: Set<TypeParameterDescriptor> - - init { - if (freeParameters.isNotEmpty()) { - // we allow to pass type parameters from another function with the same original in freeParameters - val usedTypeParameters = HashSet<TypeParameterDescriptor>().apply { addUsedTypeParameters(type) } - if (usedTypeParameters.isNotEmpty()) { - val originalFreeParameters = freeParameters.map { it.toOriginal() }.toSet() - this.freeParameters = usedTypeParameters.filter { it.toOriginal() in originalFreeParameters }.toSet() - } else { - this.freeParameters = emptySet() - } - } else { - this.freeParameters = emptySet() - } - } - - // Diagnostic for EA-109046 - @Suppress("USELESS_ELVIS") - private fun TypeParameterDescriptor.toOriginal(): TypeParameterDescriptor { - val callableDescriptor = containingDeclaration as? CallableMemberDescriptor ?: return this - val original = callableDescriptor.original ?: error("original = null for $callableDescriptor") - val typeParameters = original.typeParameters ?: error("typeParameters = null for $original") - return typeParameters[index] - } - - override fun equals(other: Any?) = other is FuzzyType && other.type == type && other.freeParameters == freeParameters - - override fun hashCode() = type.hashCode() - - private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(type: KotlinType) { - val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor - if (typeParameter != null && add(typeParameter)) { - typeParameter.upperBounds.forEach { addUsedTypeParameters(it) } - } - - for (argument in type.arguments) { - if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion - addUsedTypeParameters(argument.type) - } - } - } - - fun checkIsSubtypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUBTYPE) - - fun checkIsSuperTypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, - MatchKind.IS_SUPERTYPE - ) - - fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSubtypeOf(otherType.toFuzzyType(emptyList())) - - fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSuperTypeOf(otherType.toFuzzyType(emptyList())) - - private enum class MatchKind { - IS_SUBTYPE, - IS_SUPERTYPE - } - - private fun matchedSubstitutor(otherType: FuzzyType, matchKind: MatchKind): TypeSubstitutor? { - if (type.isError) return null - if (otherType.type.isError) return null - if (otherType.type.isUnit() && matchKind == MatchKind.IS_SUBTYPE) return TypeSubstitutor.EMPTY - - fun KotlinType.checkInheritance(otherType: KotlinType): Boolean { - return when (matchKind) { - MatchKind.IS_SUBTYPE -> this.isSubtypeOf(otherType) - MatchKind.IS_SUPERTYPE -> otherType.isSubtypeOf(this) - } - } - - if (freeParameters.isEmpty() && otherType.freeParameters.isEmpty()) { - return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null - } - - val builder = ConstraintSystemBuilderImpl() - val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters) - - val typeInSystem = typeVariableSubstitutor.substitute(type, Variance.INVARIANT) - val otherTypeInSystem = typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT) - - when (matchKind) { - MatchKind.IS_SUBTYPE -> - builder.addSubtypeConstraint(typeInSystem, otherTypeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position()) - MatchKind.IS_SUPERTYPE -> - builder.addSubtypeConstraint(otherTypeInSystem, typeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position()) - } - - builder.fixVariables() - - val constraintSystem = builder.build() - - if (constraintSystem.status.hasContradiction()) return null - - // currently ConstraintSystem return successful status in case there are problems with nullability - // that's why we have to check subtyping manually - val substitutor = constraintSystem.resultingSubstitutor - val substitutedType = substitutor.substitute(type, Variance.INVARIANT) ?: return null - if (substitutedType.isError) return TypeSubstitutor.EMPTY - val otherSubstitutedType = substitutor.substitute(otherType.type, Variance.INVARIANT) ?: return null - if (otherSubstitutedType.isError) return TypeSubstitutor.EMPTY - if (!substitutedType.checkInheritance(otherSubstitutedType)) return null - - val substitutorToKeepCapturedTypes = object : DelegatedTypeSubstitution(substitutor.substitution) { - override fun approximateCapturedTypes() = false - }.buildSubstitutor() - - val substitutionMap: Map<TypeConstructor, TypeProjection> = constraintSystem.typeVariables - .map { it.originalTypeParameter } - .associateBy( - keySelector = { it.typeConstructor }, - valueTransform = { parameterDescriptor -> - val typeProjection = TypeProjectionImpl(Variance.INVARIANT, parameterDescriptor.defaultType) - val substitutedProjection = substitutorToKeepCapturedTypes.substitute(typeProjection) - substitutedProjection?.takeUnless { ErrorUtils.containsUninferredTypeVariable(it.type) } ?: typeProjection - }) - return TypeConstructorSubstitution.createByConstructorsMap(substitutionMap, approximateCapturedTypes = true).buildSubstitutor() - } -} - - -internal fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection<TypeParameterDescriptor>): Boolean { - return freeParameters.any { parameter -> - val type = parameter.defaultType - val substituted1 = this[type] ?: return@any false - val substituted2 = other[type] ?: return@any false - !StrictEqualityTypeChecker.strictEqualTypes( - substituted1.type.unwrap(), - substituted2.type.unwrap() - ) || substituted1.projectionKind != substituted2.projectionKind - } -}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt b/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt deleted file mode 100644 index d5c4b745..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/kotlin/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - -package org.jetbrains.kotlin.resolve.lazy - -import org.jetbrains.kotlin.resolve.BindingTraceFilter - -internal enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter, val doControlFlowAnalysis: Boolean, val resolveAdditionals: Boolean = true) { - // All body statements are analyzed, diagnostics included - FULL(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true), - - // Analyzes only dependent statements, including all declaration statements (difference from PARTIAL_WITH_CFA) - PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true), - - // Analyzes only dependent statements, diagnostics included - PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true), - - // Analyzes only dependent statements, performs control flow analysis (mostly needed for isUsedAsExpression / AsStatement) - PARTIAL_WITH_CFA(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true), - - // Analyzes only dependent statements, including only used declaration statements, does not perform control flow analysis - PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false), - - // Resolve mode to resolve only the element itself without the additional elements (annotation resolve would not lead to function resolve or default parameters) - PARTIAL_NO_ADDITIONAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false, resolveAdditionals = false) - ; - - fun doesNotLessThan(other: BodyResolveMode): Boolean { - return this <= other && this.bindingTraceFilter.includesEverythingIn(other.bindingTraceFilter) - } -} diff --git a/subprojects/analysis-kotlin-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/subprojects/analysis-kotlin-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin deleted file mode 100644 index ceff7e6c..00000000 --- a/subprojects/analysis-kotlin-descriptors/ide/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. -# - -org.jetbrains.dokka.analysis.kotlin.descriptors.ide.IdeDescriptorAnalysisPlugin diff --git a/subprojects/analysis-kotlin-symbols/README.md b/subprojects/analysis-kotlin-symbols/README.md deleted file mode 100644 index 12e3041c..00000000 --- a/subprojects/analysis-kotlin-symbols/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Analysis: Kotlin symbols - -An internal symbols-based implementation for [analysis-kotlin-api](../analysis-kotlin-api), also known as K2 or -"the new compiler". - -Contains no stable public API and must not be used by anyone directly, only via [analysis-kotlin-api](../analysis-kotlin-api). - -Can be added as a runtime dependency by the runner. diff --git a/subprojects/analysis-kotlin-symbols/api/analysis-kotlin-symbols.api b/subprojects/analysis-kotlin-symbols/api/analysis-kotlin-symbols.api deleted file mode 100644 index 4bddfcf1..00000000 --- a/subprojects/analysis-kotlin-symbols/api/analysis-kotlin-symbols.api +++ /dev/null @@ -1,19 +0,0 @@ -public final class org/jetbrains/dokka/analysis/kotlin/symbols/plugin/SymbolsAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { - public fun <init> ()V -} - -public class org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinSampleProvider : org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider { - public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public fun close ()V - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; - public fun getSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet; - protected fun processBody (Lcom/intellij/psi/PsiElement;)Ljava/lang/String; - protected fun processImports (Lcom/intellij/psi/PsiElement;)Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinSampleProviderFactory : org/jetbrains/dokka/analysis/kotlin/internal/SampleProviderFactory { - public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public fun build ()Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider; - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; -} - diff --git a/subprojects/analysis-kotlin-symbols/build.gradle.kts b/subprojects/analysis-kotlin-symbols/build.gradle.kts deleted file mode 100644 index 610462a3..00000000 --- a/subprojects/analysis-kotlin-symbols/build.gradle.kts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -import org.jetbrains.DokkaPublicationBuilder -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) - compileOnly(projects.subprojects.analysisKotlinApi) - - implementation(projects.subprojects.analysisMarkdownJb) - implementation(projects.subprojects.analysisJavaPsi) - - - // ----------- IDE dependencies ---------------------------------------------------------------------------- - - listOf( - libs.intellij.platform.util.rt, - libs.intellij.platform.util.api, - libs.intellij.java.psi.api, - libs.intellij.java.psi.impl - ).forEach { - runtimeOnly(it) { isTransitive = false } - } - - implementation(libs.intellij.java.psi.api) { isTransitive = false } - - - // TODO move to toml - listOf( - "com.jetbrains.intellij.platform:util-class-loader", - "com.jetbrains.intellij.platform:util-text-matching", - "com.jetbrains.intellij.platform:util-base", - "com.jetbrains.intellij.platform:util-xml-dom", - "com.jetbrains.intellij.platform:core-impl", - "com.jetbrains.intellij.platform:extensions", - ).forEach { - runtimeOnly("$it:213.7172.25") { isTransitive = false } - } - - implementation("com.jetbrains.intellij.platform:core:213.7172.25") { - isTransitive = false - } // for Standalone prototype - - // ----------- Analysis dependencies ---------------------------------------------------------------------------- - - listOf( - libs.kotlin.high.level.api.api, - libs.kotlin.analysis.api.standalone, - ).forEach { - implementation(it) { - isTransitive = false // see KTIJ-19820 - } - } - listOf( - libs.kotlin.high.level.api.impl, - libs.kotlin.high.level.api.fir, - libs.kotlin.high.level.api.fe10, - libs.kotlin.low.level.api.fir, - libs.kotlin.analysis.project.structure, - libs.kotlin.analysis.api.providers, - libs.kotlin.symbol.light.classes, - ).forEach { - runtimeOnly(it) { - isTransitive = false // see KTIJ-19820 - } - } - // copy-pasted from Analysis API https://github.com/JetBrains/kotlin/blob/a10042f9099e20a656dec3ecf1665eea340a3633/analysis/low-level-api-fir/build.gradle.kts#L37 - runtimeOnly("com.github.ben-manes.caffeine:caffeine:2.9.3") - - runtimeOnly(libs.kotlinx.collections.immutable) - implementation(libs.kotlin.compiler.k2) { - isTransitive = false - } - - // TODO [beresnev] get rid of it - compileOnly(libs.kotlinx.coroutines.core) -} - -tasks { - shadowJar { - val dokka_version: String by project - - // cannot be named exactly like the artifact (i.e analysis-kotlin-symbols-VER.jar), - // otherwise leads to obscure test failures when run via CLI, but not via IJ - archiveFileName.set("analysis-kotlin-symbols-all-$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("analysisKotlinSymbols") { - artifactId = "analysis-kotlin-symbols" - component = DokkaPublicationBuilder.Component.Shadow -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt deleted file mode 100644 index d8a4e476..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc - -import com.intellij.psi.PsiNamedElement -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.dokka.analysis.java.parsers.JavadocParser -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol -import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType -import org.jetbrains.kotlin.psi.psiUtil.getChildOfType -import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType -import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter -import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly - -internal fun KtAnalysisSession.getJavaDocDocumentationFrom( - symbol: KtSymbol, - javadocParser: JavadocParser -): DocumentationNode? { - if (symbol.origin == KtSymbolOrigin.JAVA) { - return (symbol.psi as? PsiNamedElement)?.let { - javadocParser.parseDocumentation(it) - } - } else if (symbol.origin == KtSymbolOrigin.SOURCE && symbol is KtCallableSymbol) { - // Note: javadocParser searches in overridden JAVA declarations for JAVA method, not Kotlin - symbol.getAllOverriddenSymbols().forEach { overrider -> - if (overrider.origin == KtSymbolOrigin.JAVA) - return@getJavaDocDocumentationFrom (overrider.psi as? PsiNamedElement)?.let { - javadocParser.parseDocumentation(it) - } - } - } - return null -} - -internal fun KtAnalysisSession.getKDocDocumentationFrom(symbol: KtSymbol, logger: DokkaLogger) = findKDoc(symbol)?.let { kDocContent -> - - val ktElement = symbol.psi - val kdocLocation = ktElement?.containingFile?.name?.let { - val name = when(symbol) { - is KtCallableSymbol -> symbol.callableIdIfNonLocal?.toString() - is KtClassOrObjectSymbol -> symbol.classIdIfNonLocal?.toString() - is KtNamedSymbol -> symbol.name.asString() - else -> null - }?.replace('/', '.') // replace to be compatible with K1 - - if (name != null) "$it/$name" - else it - } - - - parseFromKDocTag( - kDocTag = kDocContent.contentTag, - externalDri = { link -> resolveKDocLink(link).ifUnresolved { logger.logUnresolvedLink(link.getLinkText(), kdocLocation) } }, - kdocLocation = kdocLocation - ) -} - - - - -// ----------- copy-paste from IDE ---------------------------------------------------------------------------- - -internal data class KDocContent( - val contentTag: KDocTag, - val sections: List<KDocSection> -) - -internal fun KtAnalysisSession.findKDoc(symbol: KtSymbol): KDocContent? { - // for generated function (e.g. `copy`) psi returns class, see test `data class kdocs over generated methods` - if (symbol.origin != KtSymbolOrigin.SOURCE) return null - val ktElement = symbol.psi as? KtElement - ktElement?.findKDoc()?.let { - return it - } - - if (symbol is KtCallableSymbol) { - symbol.getAllOverriddenSymbols().forEach { overrider -> - findKDoc(overrider)?.let { - return it - } - } - } - return null -} - - -internal fun KtElement.findKDoc(): KDocContent? = this.lookupOwnedKDoc() - ?: this.lookupKDocInContainer() - - - -private fun KtElement.lookupOwnedKDoc(): KDocContent? { - // KDoc for primary constructor is located inside of its class KDoc - val psiDeclaration = when (this) { - is KtPrimaryConstructor -> getContainingClassOrObject() - else -> this - } - - if (psiDeclaration is KtDeclaration) { - val kdoc = psiDeclaration.docComment - if (kdoc != null) { - if (this is KtConstructor<*>) { - // ConstructorDescriptor resolves to the same JetDeclaration - val constructorSection = kdoc.findSectionByTag(KDocKnownTag.CONSTRUCTOR) - if (constructorSection != null) { - // if annotated with @constructor tag and the caret is on constructor definition, - // then show @constructor description as the main content, and additional sections - // that contain @param tags (if any), as the most relatable ones - // practical example: val foo = Fo<caret>o("argument") -- show @constructor and @param content - val paramSections = kdoc.findSectionsContainingTag(KDocKnownTag.PARAM) - return KDocContent(constructorSection, paramSections) - } - } - return KDocContent(kdoc.getDefaultSection(), kdoc.getAllSections()) - } - } - - return null -} - -/** - * Looks for sections that have a deeply nested [tag], - * as opposed to [KDoc.findSectionByTag], which only looks among the top level - */ -private fun KDoc.findSectionsContainingTag(tag: KDocKnownTag): List<KDocSection> { - return getChildrenOfType<KDocSection>() - .filter { it.findTagByName(tag.name.toLowerCaseAsciiOnly()) != null } -} - -private fun KtElement.lookupKDocInContainer(): KDocContent? { - val subjectName = name - val containingDeclaration = - PsiTreeUtil.findFirstParent(this, true) { - it is KtDeclarationWithBody && it !is KtPrimaryConstructor - || it is KtClassOrObject - } - - val containerKDoc = containingDeclaration?.getChildOfType<KDoc>() - if (containerKDoc == null || subjectName == null) return null - val propertySection = containerKDoc.findSectionByTag(KDocKnownTag.PROPERTY, subjectName) - val paramTag = - containerKDoc.findDescendantOfType<KDocTag> { it.knownTag == KDocKnownTag.PARAM && it.getSubjectName() == subjectName } - - val primaryContent = when { - // class Foo(val <caret>s: String) - this is KtParameter && this.isPropertyParameter() -> propertySection ?: paramTag - // fun some(<caret>f: String) || class Some<<caret>T: Base> || Foo(<caret>s = "argument") - this is KtParameter || this is KtTypeParameter -> paramTag - // if this property is declared separately (outside primary constructor), but it's for some reason - // annotated as @property in class's description, instead of having its own KDoc - this is KtProperty && containingDeclaration is KtClassOrObject -> propertySection - else -> null - } - return primaryContent?.let { - // makes little sense to include any other sections, since we found - // documentation for a very specific element, like a property/param - KDocContent(it, sections = emptyList()) - } -} - diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KdocMarkdownParser.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KdocMarkdownParser.kt deleted file mode 100644 index ad29f5f0..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KdocMarkdownParser.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.analysis.markdown.jb.MarkdownParser -import org.jetbrains.dokka.analysis.markdown.jb.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.KDocLink -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.psiUtil.allChildren - -internal fun parseFromKDocTag( - kDocTag: KDocTag?, - externalDri: (KDocLink) -> DRI?, - kdocLocation: String?, - parseWithChildren: Boolean = true -): DocumentationNode { - return if (kDocTag == null) { - DocumentationNode(emptyList()) - } else { - fun parseStringToDocNode(text: String, externalDRIProvider: (String) -> DRI?) = - MarkdownParser(externalDRIProvider, kdocLocation).parseStringToDocNode(text) - - fun pointedLink(tag: KDocTag): DRI? = tag.getSubjectLink()?.let(externalDri) - - val allTags = - listOf(kDocTag) + if (kDocTag.canHaveParent() && parseWithChildren) getAllKDocTags(findParent(kDocTag)) else emptyList() - DocumentationNode( - allTags.map { tag -> - val links = tag.allChildren.filterIsInstance<KDocLink>().associate { it.getLinkText() to externalDri(it) } - val externalDRIProvider = { linkText: String -> links[linkText] } - - when (tag.knownTag) { - null -> if (tag.name == null) Description(parseStringToDocNode(tag.getContent(), externalDRIProvider)) else CustomTagWrapper( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - tag.name!! - ) - KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - KDocKnownTag.THROWS -> { - val dri = pointedLink(tag) - Throws( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - dri?.fqDeclarationName() ?: tag.getSubjectName().orEmpty(), - dri, - ) - } - KDocKnownTag.EXCEPTION -> { - val dri = pointedLink(tag) - Throws( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - dri?.fqDeclarationName() ?: tag.getSubjectName().orEmpty(), - dri - ) - } - KDocKnownTag.PARAM -> Param( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - tag.getSubjectName().orEmpty() - ) - KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - KDocKnownTag.RETURN -> Return(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - KDocKnownTag.SEE -> { - val dri = pointedLink(tag) - See( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - dri?.fqDeclarationName() ?: tag.getSubjectName().orEmpty(), - dri, - ) - } - KDocKnownTag.SINCE -> Since(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - KDocKnownTag.PROPERTY -> Property( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - tag.getSubjectName().orEmpty() - ) - KDocKnownTag.SAMPLE -> Sample( - parseStringToDocNode(tag.getContent(), externalDRIProvider), - tag.getSubjectName().orEmpty() - ) - KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(tag.getContent(), externalDRIProvider)) - } - } - ) - } -} - -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<KDocTag> = - kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { - getAllKDocTags(it) - } diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt deleted file mode 100644 index 9a0b81bd..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getDRIFromSymbol -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink -import org.jetbrains.kotlin.kdoc.psi.impl.KDocName -import org.jetbrains.kotlin.psi.KtPsiFactory - -/** - * Util to print a message about unresolved [link] - */ -internal fun DokkaLogger.logUnresolvedLink(link: String, location: String?) { - warn("Couldn't resolve link for $link" + if (location != null) " in $location" else "") -} - -internal inline fun DRI?.ifUnresolved(action: () -> Unit): DRI? = this ?: run { - action() - null -} - -/** - * Resolves KDoc link via creating PSI. - * If the [link] is ambiguous, i.e. leads to more than one declaration, - * it returns deterministically any declaration. - * - * @return [DRI] or null if the [link] is unresolved - */ -internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiElement? = null): DRI? { - val psiFactory = context?.let { KtPsiFactory.contextual(it) } ?: KtPsiFactory(this.useSiteModule.project) - val kDoc = psiFactory.createComment( - """ - /** - * [$link] - */ - """.trimIndent() - ) as? KDoc - val kDocLink = kDoc?.getDefaultSection()?.children?.filterIsInstance<KDocLink>()?.singleOrNull() - return kDocLink?.let { resolveKDocLink(it) } -} - -/** - * If the [link] is ambiguous, i.e. leads to more than one declaration, - * it returns deterministically any declaration. - * - * @return [DRI] or null if the [link] is unresolved - */ -internal fun KtAnalysisSession.resolveKDocLink(link: KDocLink): DRI? { - val lastNameSegment = link.children.filterIsInstance<KDocName>().lastOrNull() - val linkedSymbol = lastNameSegment?.mainReference?.resolveToSymbols()?.firstOrNull() - return if (linkedSymbol == null) null - else getDRIFromSymbol(linkedSymbol) -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt deleted file mode 100644 index 4622ffd8..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc - -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -import org.jetbrains.dokka.analysis.markdown.jb.MarkdownParser -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.symbols.* -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol -import org.jetbrains.kotlin.builtins.StandardNames - -private const val ENUM_ENTRIES_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumEntries.kt.template" -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 fun KtAnalysisSession.hasGeneratedKDocDocumentation(symbol: KtSymbol): Boolean = - getDocumentationTemplatePath(symbol) != null - -private fun KtAnalysisSession.getDocumentationTemplatePath(symbol: KtSymbol): String? = - when (symbol) { - is KtPropertySymbol -> if (isEnumEntriesProperty(symbol)) ENUM_ENTRIES_TEMPLATE_PATH else null - is KtFunctionSymbol -> { - when { - isEnumValuesMethod(symbol) -> ENUM_VALUES_TEMPLATE_PATH - isEnumValueOfMethod(symbol) -> ENUM_VALUEOF_TEMPLATE_PATH - else -> null - } - } - - else -> null - } - -private fun KtAnalysisSession.isEnumSpecialMember(symbol: KtPossibleMemberSymbol): Boolean = - symbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED - && (symbol.getContainingSymbol() as? KtClassOrObjectSymbol)?.classKind == KtClassKind.ENUM_CLASS - -private fun KtAnalysisSession.isEnumEntriesProperty(symbol: KtPropertySymbol): Boolean = - symbol.name == StandardNames.ENUM_ENTRIES && isEnumSpecialMember(symbol) - -private fun KtAnalysisSession.isEnumValuesMethod(symbol: KtFunctionSymbol): Boolean = - symbol.name == StandardNames.ENUM_VALUES && isEnumSpecialMember(symbol) - -private fun KtAnalysisSession.isEnumValueOfMethod(symbol: KtFunctionSymbol): Boolean = - symbol.name == StandardNames.ENUM_VALUE_OF && isEnumSpecialMember(symbol) - -internal fun KtAnalysisSession.getGeneratedKDocDocumentationFrom(symbol: KtSymbol): DocumentationNode? { - val templatePath = getDocumentationTemplatePath(symbol) ?: return null - return loadTemplate(templatePath) -} - -private fun KtAnalysisSession.loadTemplate(filePath: String): DocumentationNode? { - val kdoc = loadContent(filePath) ?: return null - val externalDriProvider = { link: String -> - resolveKDocTextLink(link) - } - - val parser = MarkdownParser(externalDriProvider, filePath) - return parser.parse(kdoc) -} - -private fun loadContent(filePath: String): String? = - SymbolsAnalysisPlugin::class.java.getResource(filePath)?.readText() diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorDocumentationContent.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorDocumentationContent.kt deleted file mode 100644 index 4db17b28..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorDocumentationContent.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java - -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent -import org.jetbrains.dokka.analysis.java.JavadocTag -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag - -internal data class DescriptorDocumentationContent( - val resolveDocContext: ResolveDocContext, - val element: KDocTag, - override val tag: JavadocTag, -) : DocumentationContent { - override fun resolveSiblings(): List<DocumentationContent> { - return listOf(this) - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorKotlinDocCommentCreator.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorKotlinDocCommentCreator.kt deleted file mode 100644 index 7a43972c..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/DescriptorKotlinDocCommentCreator.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.doccomment.DocCommentCreator -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.findKDoc -import org.jetbrains.kotlin.psi.KtElement - -internal class DescriptorKotlinDocCommentCreator : DocCommentCreator { - override fun create(element: PsiNamedElement): DocComment? { - val ktElement = element.navigationElement as? KtElement ?: return null - val kdoc = ktElement.findKDoc() ?: return null - - return KotlinDocComment(kdoc.contentTag, ResolveDocContext(ktElement)) - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocComment.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocComment.kt deleted file mode 100644 index 63c55869..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocComment.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java - -import org.jetbrains.dokka.analysis.java.* -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.psi.KtElement - -internal class ResolveDocContext(val ktElement: KtElement) - -internal class KotlinDocComment( - val comment: KDocTag, - val resolveDocContext: ResolveDocContext -) : DocComment { - - private val tagsWithContent: List<KDocTag> = 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<DocumentationContent> { - return when (tag) { - is DescriptionJavadocTag -> listOf(DescriptorDocumentationContent(resolveDocContext, 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<DescriptorDocumentationContent> { - val exceptionName = tag.exceptionQualifiedName ?: return resolveGeneric(tag) - - return comment.children - .filterIsInstance<KDocTag>() - .filter { it.name == tag.name && it.getSubjectName() == exceptionName } - .map { DescriptorDocumentationContent(resolveDocContext, it, tag) } - } - - private fun resolveGeneric(tag: JavadocTag): List<DescriptorDocumentationContent> { - return comment.children.mapNotNull { element -> - if (element is KDocTag && element.name == tag.name) { - DescriptorDocumentationContent(resolveDocContext, 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 (resolveDocContext.name != other.resolveDocContext.name) return false - if (tagsWithContent != other.tagsWithContent) return false - - return true - } - - override fun hashCode(): Int { - var result = comment.hashCode() - // result = 31 * result + resolveDocContext.name.hashCode() - result = 31 * result + tagsWithContent.hashCode() - return result - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt deleted file mode 100644 index 0ee95e45..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java - -import com.intellij.psi.PsiNamedElement -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.java.doccomment.DocComment -import org.jetbrains.dokka.analysis.java.parsers.DocCommentParser -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.* -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.parseFromKDocTag -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocLink -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -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.kotlin.analysis.api.analyze - -internal class KotlinDocCommentParser( - private val context: DokkaContext -) : 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 kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - val elementName = element.resolveDocContext.ktElement.name - return analyze(kotlinAnalysis.getModule(sourceSet)) { - parseFromKDocTag( - kDocTag = element.comment, - externalDri = { link -> resolveKDocLink(link).ifUnresolved { context.logger.logUnresolvedLink(link.getLinkText(), elementName) } }, - kdocLocation = null, - parseWithChildren = parseWithChildren - ) - } - } -} - diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinInheritDocTagContentProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinInheritDocTagContentProvider.kt deleted file mode 100644 index 4c2b7afd..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinInheritDocTagContentProvider.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java - -import org.jetbrains.dokka.analysis.java.doccomment.DocumentationContent -import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin -import org.jetbrains.dokka.analysis.java.parsers.doctag.DocTagParserContext -import org.jetbrains.dokka.analysis.java.parsers.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<JavaAnalysisPlugin>().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.resolveDocContext), - parseWithChildren = false - ) - val id = docTagParserContext.store(inheritedDocNode) - return """<inheritdoc id="$id"/>""" - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/IllegalModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/IllegalModuleAndPackageDocumentation.kt deleted file mode 100644 index a090e4d5..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/IllegalModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import org.jetbrains.dokka.DokkaException - -internal class IllegalModuleAndPackageDocumentation( - source: ModuleAndPackageDocumentationSource, message: String -) : DokkaException("[$source] $message") diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentation.kt deleted file mode 100644 index 4036d3d0..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import org.jetbrains.dokka.model.doc.DocumentationNode - -internal data class ModuleAndPackageDocumentation( - val name: String, - val classifier: Classifier, - val documentation: DocumentationNode -) { - enum class Classifier { Module, Package } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationFragment.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationFragment.kt deleted file mode 100644 index be7c915c..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationFragment.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - - -internal data class ModuleAndPackageDocumentationFragment( - val name: String, - val classifier: ModuleAndPackageDocumentation.Classifier, - val documentation: String, - val source: ModuleAndPackageDocumentationSource -) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt deleted file mode 100644 index f5cfbdb9..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.ifUnresolved -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.KotlinAnalysis -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Module -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Package -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocTextLink -import org.jetbrains.dokka.analysis.markdown.jb.MarkdownParser -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.name.FqName - -internal fun interface ModuleAndPackageDocumentationParsingContext { - fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment, location: String): MarkdownParser -} - -internal fun ModuleAndPackageDocumentationParsingContext.parse( - fragment: ModuleAndPackageDocumentationFragment -): DocumentationNode { - return markdownParserFor(fragment, fragment.source.sourceDescription).parse(fragment.documentation) -} - -internal fun ModuleAndPackageDocumentationParsingContext( - logger: DokkaLogger, - kotlinAnalysis: KotlinAnalysis? = null, - sourceSet: DokkaConfiguration.DokkaSourceSet? = null -) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation -> - - if (kotlinAnalysis == null || sourceSet == null) { - MarkdownParser(externalDri = { null }, sourceLocation) - } else { - val sourceModule = kotlinAnalysis.getModule(sourceSet) - val contextPsi = analyze(sourceModule) { - val contextSymbol = when (fragment.classifier) { - Module -> ROOT_PACKAGE_SYMBOL - Package -> getPackageSymbolIfPackageExists(FqName(fragment.name)) - } - contextSymbol?.psi - } - MarkdownParser( - externalDri = { link -> - analyze(sourceModule) { - resolveKDocTextLink( - link, - contextPsi - ).ifUnresolved { - logger.logUnresolvedLink(link, fragment.name.ifBlank { "module documentation" }) - } - - } - }, - sourceLocation - ) - - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationReader.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationReader.kt deleted file mode 100644 index ef79e885..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationReader.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.DPackage -import org.jetbrains.dokka.model.SourceSetDependent -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Deprecated -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.utilities.associateWithNotNull -import org.jetbrains.dokka.analysis.kotlin.internal.ModuleAndPackageDocumentationReader - -internal fun ModuleAndPackageDocumentationReader(context: DokkaContext): ModuleAndPackageDocumentationReader = - ContextModuleAndPackageDocumentationReader(context) - -private class ContextModuleAndPackageDocumentationReader( - private val context: DokkaContext -) : ModuleAndPackageDocumentationReader { - - private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - - private val documentationFragments: SourceSetDependent<List<ModuleAndPackageDocumentationFragment>> = - context.configuration.sourceSets.associateWith { sourceSet -> - sourceSet.includes.flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } - } - - private fun findDocumentationNodes( - sourceSets: Set<DokkaConfiguration.DokkaSourceSet>, - predicate: (ModuleAndPackageDocumentationFragment) -> Boolean - ): SourceSetDependent<DocumentationNode> { - return sourceSets.associateWithNotNull { sourceSet -> - val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate) - kotlinAnalysis.getModule(sourceSet)// test: to throw exception for unknown sourceSet - val documentations = fragments.map { fragment -> - parseModuleAndPackageDocumentation( - context = ModuleAndPackageDocumentationParsingContext(context.logger, kotlinAnalysis, sourceSet), - fragment = fragment - ) - } - when (documentations.size) { - 0 -> null - 1 -> documentations.single().documentation - else -> DocumentationNode(documentations.flatMap { it.documentation.children } - .mergeDocumentationNodes()) - } - } - } - - private val ModuleAndPackageDocumentationFragment.canonicalPackageName: String - get() { - check(classifier == Classifier.Package) - if (name == "[root]") return "" - return name - } - - override fun read(module: DModule): SourceSetDependent<DocumentationNode> { - return findDocumentationNodes(module.sourceSets) { fragment -> - fragment.classifier == Classifier.Module && (fragment.name == module.name) - } - } - - override fun read(pkg: DPackage): SourceSetDependent<DocumentationNode> { - 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<TagWrapper>.mergeDocumentationNodes(): List<TagWrapper> = - groupBy { it::class }.values.map { - it.reduce { acc, tagWrapper -> - val newRoot = CustomDocTag( - acc.children + tagWrapper.children, - name = (tagWrapper as? NamedTagWrapper)?.name.orEmpty() - ) - when (acc) { - is See -> acc.copy(newRoot) - is Param -> acc.copy(newRoot) - is Throws -> acc.copy(newRoot) - is Sample -> acc.copy(newRoot) - is Property -> acc.copy(newRoot) - is CustomTagWrapper -> acc.copy(newRoot) - is Description -> acc.copy(newRoot) - is Author -> acc.copy(newRoot) - is Version -> acc.copy(newRoot) - is Since -> acc.copy(newRoot) - is Return -> acc.copy(newRoot) - is Receiver -> acc.copy(newRoot) - is Constructor -> acc.copy(newRoot) - is Deprecated -> acc.copy(newRoot) - is org.jetbrains.dokka.model.doc.Suppress -> acc.copy(newRoot) - } - } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationSource.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationSource.kt deleted file mode 100644 index f994eb36..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import java.io.File - -internal abstract class ModuleAndPackageDocumentationSource { - abstract val sourceDescription: String - abstract val documentation: String - override fun toString(): String = sourceDescription -} - -internal data class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { - override val sourceDescription: String = file.path - override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentation.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentation.kt deleted file mode 100644 index 176a487b..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -internal fun parseModuleAndPackageDocumentation( - context: ModuleAndPackageDocumentationParsingContext, - fragment: ModuleAndPackageDocumentationFragment -): ModuleAndPackageDocumentation { - return ModuleAndPackageDocumentation( - name = fragment.name, - classifier = fragment.classifier, - documentation = context.parse(fragment) - ) -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentationFragments.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentationFragments.kt deleted file mode 100644 index 621b06f0..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/parseModuleAndPackageDocumentationFragments.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs - -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Module -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Package -import java.io.File - -internal fun parseModuleAndPackageDocumentationFragments(source: File): List<ModuleAndPackageDocumentationFragment> { - return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source)) -} - -internal fun parseModuleAndPackageDocumentationFragments( - source: ModuleAndPackageDocumentationSource -): List<ModuleAndPackageDocumentationFragment> { - val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) - return fragmentStrings - .filter(String::isNotBlank) - .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } -} - -private fun parseModuleAndPackageDocFragment( - source: ModuleAndPackageDocumentationSource, - fragment: String -): ModuleAndPackageDocumentationFragment { - val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) - val firstLine = firstLineAndDocumentation[0] - - val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) - - val classifier = when (classifierAndName[0].trim()) { - "Module" -> Module - "Package" -> Package - else -> throw IllegalStateException( - """Unexpected classifier: "${classifierAndName[0]}", expected either "Module" or "Package". - |For more information consult the specification: https://kotlinlang.org/docs/dokka-module-and-package-docs.html""".trimMargin() - ) - } - - if (classifierAndName.size != 2 && classifier == Module) { - throw IllegalModuleAndPackageDocumentation(source, "Missing Module name") - } - - val name = classifierAndName.getOrNull(1)?.trim().orEmpty() - if (classifier == Package && name.contains(Regex("\\s"))) { - throw IllegalModuleAndPackageDocumentation( - source, "Package name cannot contain whitespace in '$firstLine'" - ) - } - - return ModuleAndPackageDocumentationFragment( - name = name, - classifier = classifier, - documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty(), - source = source - ) -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt deleted file mode 100644 index 191c5f92..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/AnalysisContext.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.plugin - -import com.intellij.openapi.Disposable -import com.intellij.openapi.util.Disposer -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.model.SourceSetDependent -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession -import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule -import java.io.Closeable - -internal fun SamplesKotlinAnalysis( - sourceSets: List<DokkaConfiguration.DokkaSourceSet>, - context: DokkaContext, -): KotlinAnalysis = createAnalysisSession( - sourceSets = sourceSets, - logger = context.logger, - isSampleProject = true -) - -internal fun ProjectKotlinAnalysis( - sourceSets: List<DokkaConfiguration.DokkaSourceSet>, - context: DokkaContext, -): KotlinAnalysis = createAnalysisSession( - sourceSets = sourceSets, - logger = context.logger -) - -internal class KotlinAnalysis( - private val sourceModules: SourceSetDependent<KtSourceModule>, - private val analysisSession: StandaloneAnalysisAPISession, - private val applicationDisposable: Disposable, - private val projectDisposable: Disposable -) : Closeable { - - fun getModule(sourceSet: DokkaConfiguration.DokkaSourceSet) = - sourceModules[sourceSet] ?: error("Missing a source module for sourceSet ${sourceSet.displayName} with id ${sourceSet.sourceSetID}") - - fun getModuleOrNull(sourceSet: DokkaConfiguration.DokkaSourceSet) = - sourceModules[sourceSet] - - val modulesWithFiles - get() = analysisSession.modulesWithFiles - - override fun close() { - Disposer.dispose(applicationDisposable) - Disposer.dispose(projectDisposable) - } -}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt deleted file mode 100644 index e074a142..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/KotlinAnalysis.kt +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.plugin - -import com.intellij.openapi.Disposable -import com.intellij.openapi.util.Disposer -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals -import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider -import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider -import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession -import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule -import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleBuilder -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.platform.CommonPlatforms -import org.jetbrains.kotlin.platform.js.JsPlatforms -import org.jetbrains.kotlin.platform.jvm.JvmPlatforms -import org.jetbrains.kotlin.platform.konan.NativePlatforms -import java.io.File - -internal fun Platform.toTargetPlatform() = when (this) { - Platform.js, Platform.wasm -> JsPlatforms.defaultJsPlatform - Platform.common -> CommonPlatforms.defaultCommonPlatform - Platform.native -> NativePlatforms.unspecifiedNativePlatform - Platform.jvm -> JvmPlatforms.defaultJvmPlatform -} - -private fun getJdkHomeFromSystemProperty(logger: DokkaLogger): File? { - val javaHome = File(System.getProperty("java.home")) - if (!javaHome.exists()) { - logger.error("Set existed java.home to use JDK") - return null - } - return javaHome -} - -internal fun getLanguageVersionSettings( - languageVersionString: String?, - apiVersionString: String? -): LanguageVersionSettingsImpl { - val languageVersion = LanguageVersion.fromVersionString(languageVersionString) ?: LanguageVersion.LATEST_STABLE - val apiVersion = - apiVersionString?.let { ApiVersion.parse(it) } ?: ApiVersion.createByLanguageVersion(languageVersion) - return LanguageVersionSettingsImpl( - languageVersion = languageVersion, - apiVersion = apiVersion, analysisFlags = hashMapOf( - // special flag for Dokka - // force to resolve light classes (lazily by default) - AnalysisFlags.eagerResolveOfLightClasses to true - ) - ) -} - -@OptIn(KtAnalysisApiInternals::class) -internal fun createAnalysisSession( - sourceSets: List<DokkaConfiguration.DokkaSourceSet>, - logger: DokkaLogger, - applicationDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.application"), - projectDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.project"), - isSampleProject: Boolean = false -): KotlinAnalysis { - val sourcesModule = mutableMapOf<DokkaConfiguration.DokkaSourceSet, KtSourceModule>() - - val analysisSession = buildStandaloneAnalysisAPISession( - applicationDisposable = applicationDisposable, - projectDisposable = projectDisposable, - withPsiDeclarationFromBinaryModuleProvider = false - ) { - registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) - - val sortedSourceSets = topologicalSortByDependantSourceSets(sourceSets, logger) - - val sourcesModuleBySourceSetId = mutableMapOf<DokkaSourceSetID, KtSourceModule>() - - buildKtModuleProvider { - val jdkModule = getJdkHomeFromSystemProperty(logger)?.let { jdkHome -> - buildKtSdkModule { - this.platform = Platform.jvm.toTargetPlatform() - addBinaryRootsFromJdkHome(jdkHome.toPath(), isJre = true) - sdkName = "JDK" - } - } - - fun KtModuleBuilder.addModuleDependencies(sourceSet: DokkaConfiguration.DokkaSourceSet) { - val targetPlatform = sourceSet.analysisPlatform.toTargetPlatform() - addRegularDependency( - buildKtLibraryModule { - this.platform = targetPlatform - addBinaryRoots(sourceSet.classpath.map { it.toPath() }) - libraryName = "Library for ${sourceSet.displayName}" - } - ) - if (sourceSet.analysisPlatform == Platform.jvm) { - jdkModule?.let { addRegularDependency(it) } - } - sourceSet.dependentSourceSets.forEach { - addRegularDependency( - sourcesModuleBySourceSetId[it] - ?: error("There is no source module for $it") - ) - } - } - - for (sourceSet in sortedSourceSets) { - val targetPlatform = sourceSet.analysisPlatform.toTargetPlatform() - val sourceModule = buildKtSourceModule { - languageVersionSettings = - getLanguageVersionSettings(sourceSet.languageVersion, sourceSet.apiVersion) - platform = targetPlatform - moduleName = "<module ${sourceSet.displayName}>" - if (isSampleProject) - addSourceRoots(sourceSet.samples.map { it.toPath() }) - else - addSourceRoots(sourceSet.sourceRoots.map { it.toPath() }) - addModuleDependencies( - sourceSet, - ) - } - sourcesModule[sourceSet] = sourceModule - sourcesModuleBySourceSetId[sourceSet.sourceSetID] = sourceModule - addModule(sourceModule) - } - platform = sourceSets.map { it.analysisPlatform }.distinct().singleOrNull()?.toTargetPlatform() - ?: Platform.common.toTargetPlatform() - } - } - return KotlinAnalysis(sourcesModule, analysisSession, applicationDisposable, projectDisposable) -} - -private enum class State { - UNVISITED, - VISITING, - VISITED; -} - -internal fun topologicalSortByDependantSourceSets( - sourceSets: List<DokkaConfiguration.DokkaSourceSet>, - logger: DokkaLogger -): List<DokkaConfiguration.DokkaSourceSet> { - val result = mutableListOf<DokkaConfiguration.DokkaSourceSet>() - - val verticesAssociatedWithState = sourceSets.associateWithTo(mutableMapOf()) { State.UNVISITED } - fun dfs(souceSet: DokkaConfiguration.DokkaSourceSet) { - when (verticesAssociatedWithState[souceSet]) { - State.VISITED -> return - State.VISITING -> { - logger.error("Detected cycle in source set graph") - return - } - - else -> { - val dependentSourceSets = - souceSet.dependentSourceSets.mapNotNull { dependentSourceSetId -> - sourceSets.find { it.sourceSetID == dependentSourceSetId } - // just skip - ?: null.also { logger.error("Unknown source set Id $dependentSourceSetId in dependencies of ${souceSet.sourceSetID}") } - } - verticesAssociatedWithState[souceSet] = State.VISITING - dependentSourceSets.forEach(::dfs) - verticesAssociatedWithState[souceSet] = State.VISITED - result += souceSet - } - } - } - sourceSets.forEach(::dfs) - return result -}
\ No newline at end of file diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/SymbolsAnalysisPlugin.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/SymbolsAnalysisPlugin.kt deleted file mode 100644 index 122e0b10..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/plugin/SymbolsAnalysisPlugin.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.plugin - -import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute -import com.intellij.psi.PsiAnnotation -import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.analysis.java.BreakingAbstractionKotlinLightMethodChecker -import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java.KotlinInheritDocTagContentProvider -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java.DescriptorKotlinDocCommentCreator -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.java.KotlinDocCommentParser -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentationReader -import org.jetbrains.dokka.analysis.kotlin.symbols.services.KotlinAnalysisSourceRootsExtractor -import org.jetbrains.dokka.analysis.kotlin.symbols.services.* -import org.jetbrains.dokka.analysis.kotlin.symbols.services.KotlinDocumentableSourceLanguageParser -import org.jetbrains.dokka.analysis.kotlin.symbols.services.SymbolExternalDocumentablesProvider -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.DefaultSymbolToDocumentableTranslator -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.asJava.elements.KtLightAbstractAnnotation - -@Suppress("unused") -public class SymbolsAnalysisPlugin : DokkaPlugin() { - - internal val kotlinAnalysis by extensionPoint<KotlinAnalysis>() - - internal val defaultKotlinAnalysis by extending { - kotlinAnalysis providing { ctx -> - ProjectKotlinAnalysis( - sourceSets = ctx.configuration.sourceSets, - context = ctx - ) - } - } - - internal val disposeKotlinAnalysisPostAction by extending { - CoreExtensions.postActions with PostAction { querySingle { kotlinAnalysis }.close() } - } - - internal val symbolToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator providing ::DefaultSymbolToDocumentableTranslator - } - - private val javaAnalysisPlugin by lazy { plugin<JavaAnalysisPlugin>() } - - 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 { - DescriptorKotlinDocCommentCreator() - } - } - - internal val kotlinDocCommentParser by extending { - javaAnalysisPlugin.docCommentParsers providing { context -> - KotlinDocCommentParser( - context - ) - } - } - 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 symbolAnalyzerImpl by extending { - plugin<InternalKotlinAnalysisPlugin>().documentableSourceLanguageParser providing { KotlinDocumentableSourceLanguageParser() } - } - - internal val symbolFullClassHierarchyBuilder by extending { - plugin<InternalKotlinAnalysisPlugin>().fullClassHierarchyBuilder providing ::SymbolFullClassHierarchyBuilder - } - - internal val symbolSyntheticDocumentableDetector by extending { - plugin<InternalKotlinAnalysisPlugin>().syntheticDocumentableDetector providing { SymbolSyntheticDocumentableDetector() } - } - - internal val moduleAndPackageDocumentationReader by extending { - plugin<InternalKotlinAnalysisPlugin>().moduleAndPackageDocumentationReader providing ::ModuleAndPackageDocumentationReader - } - - internal val kotlinToJavaMapper by extending { - plugin<InternalKotlinAnalysisPlugin>().kotlinToJavaService providing { SymbolKotlinToJavaMapper() } - } - - internal val symbolInheritanceBuilder by extending { - plugin<InternalKotlinAnalysisPlugin>().inheritanceBuilder providing ::SymbolInheritanceBuilder - } - - internal val symbolExternalDocumentablesProvider by extending { - plugin<InternalKotlinAnalysisPlugin>().externalDocumentablesProvider providing ::SymbolExternalDocumentablesProvider - } - - internal val kotlinSampleProviderFactory by extending { - plugin<InternalKotlinAnalysisPlugin>().sampleProviderFactory providing ::KotlinSampleProviderFactory - } - - @OptIn(DokkaPluginApiPreview::class) - override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisProjectProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisProjectProvider.kt deleted file mode 100644 index 398d48ee..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisProjectProvider.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.openapi.project.Project -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.ProjectProvider -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -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<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - return kotlinAnalysis.getModule(sourceSet).project - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisSourceRootsExtractor.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisSourceRootsExtractor.kt deleted file mode 100644 index 01084eab..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinAnalysisSourceRootsExtractor.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.SourceRootsExtractor -import org.jetbrains.dokka.plugability.DokkaContext -import java.io.File - -internal class KotlinAnalysisSourceRootsExtractor : SourceRootsExtractor { - override fun extract(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext): List<File> { - return sourceSet.sourceRoots.filter { directory -> directory.isDirectory || directory.extension == "java" } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinDocumentableSourceLanguageParser.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinDocumentableSourceLanguageParser.kt deleted file mode 100644 index ae0d79ee..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinDocumentableSourceLanguageParser.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.model.WithSources -import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableLanguage -import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableSourceLanguageParser - -internal class KotlinDocumentableSourceLanguageParser : DocumentableSourceLanguageParser { - - /** - * For members inherited from Java in Kotlin - it returns [DocumentableLanguage.KOTLIN] - */ - 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 KtPsiDocumentableSource -> DocumentableLanguage.KOTLIN - else -> error("Unknown language sources: ${documentableSource::class}") - } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinSampleProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinSampleProvider.kt deleted file mode 100644 index e453c72d..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KotlinSampleProvider.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProvider -import org.jetbrains.dokka.analysis.kotlin.internal.SampleProviderFactory -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SamplesKotlinAnalysis -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.psi.KtFile - -public class KotlinSampleProviderFactory( - public val context: DokkaContext -): SampleProviderFactory { - override fun build(): SampleProvider { - return KotlinSampleProvider(context) - } - -} -/** - * It's declared as open since StdLib has its own sample transformer - * with [processBody] and [processImports] - */ -@InternalDokkaApi -public open class KotlinSampleProvider( - public val context: DokkaContext -): SampleProvider { - private val kotlinAnalysisOfRegularSources = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - - private val kotlinAnalysisOfSamples = SamplesKotlinAnalysis( - sourceSets = context.configuration.sourceSets, context = context - ) - - protected open fun processBody(psiElement: PsiElement): String { - val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd() - val lines = text.split("\n") - val indent = lines.filter(String::isNotBlank).minOfOrNull { it.takeWhile(Char::isWhitespace).count() } ?: 0 - return lines.joinToString("\n") { it.drop(indent) } - } - - private fun processSampleBody(psiElement: PsiElement): String = when (psiElement) { - is KtDeclarationWithBody -> { - when (val bodyExpression = psiElement.bodyExpression) { - is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") - else -> bodyExpression!!.text - } - } - else -> psiElement.text - } - - protected open fun processImports(psiElement: PsiElement): String { - val psiFile = psiElement.containingFile - return when(val text = (psiFile as? KtFile)?.importList?.text) { - is String -> text - else -> "" - } - } - - /** - * @return [SampleProvider.SampleSnippet] or null if it has not found by [fqLink] - */ - override fun getSample(sourceSet: DokkaConfiguration.DokkaSourceSet, fqLink: String): SampleProvider.SampleSnippet? { - return kotlinAnalysisOfSamples.getModuleOrNull(sourceSet)?.let { getSampleFromModule(it, fqLink) } - ?: getSampleFromModule( - kotlinAnalysisOfRegularSources.getModule(sourceSet), fqLink - ) - } - private fun getSampleFromModule(module: KtSourceModule, fqLink: String): SampleProvider.SampleSnippet? { - val psiElement = analyze(module) { - val lastDotIndex = fqLink.lastIndexOf('.') - - val functionName = if (lastDotIndex == -1) fqLink else fqLink.substring(lastDotIndex + 1, fqLink.length) - val packageName = if (lastDotIndex == -1) "" else fqLink.substring(0, lastDotIndex) - getTopLevelCallableSymbols(FqName(packageName), Name.identifier(functionName)).firstOrNull()?.psi - } - ?: return null.also { context.logger.warn("Cannot find PsiElement corresponding to $fqLink") } - val imports = - processImports(psiElement) - val body = processBody(psiElement) - - return SampleProvider.SampleSnippet(imports, body) - } - - override fun close() { - kotlinAnalysisOfSamples.close() - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KtPsiDocumentableSource.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KtPsiDocumentableSource.kt deleted file mode 100644 index 284da189..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/KtPsiDocumentableSource.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.model.DocumentableSource -import org.jetbrains.kotlin.lexer.KtTokens - - -internal class KtPsiDocumentableSource(val psi: PsiElement?) : DocumentableSource { - override val path = psi?.containingFile?.virtualFile?.path ?: "" - - override fun computeLineNumber(): Int? { - return psi?.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/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolExternalDocumentablesProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolExternalDocumentablesProvider.kt deleted file mode 100644 index 1473a7da..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolExternalDocumentablesProvider.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.DokkaSymbolVisitor -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getClassIdFromDRI -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getDRIFromSymbol -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.DClasslike -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol -import org.jetbrains.dokka.analysis.kotlin.internal.ExternalDocumentablesProvider - -internal class SymbolExternalDocumentablesProvider(val context: DokkaContext) : ExternalDocumentablesProvider { - private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - - override fun findClasslike(dri: DRI, sourceSet: DokkaSourceSet): DClasslike? { - val classId = getClassIdFromDRI(dri) - - return analyze(kotlinAnalysis.getModule(sourceSet)) { - val symbol = getClassOrObjectSymbolByClassId(classId) as? KtNamedClassOrObjectSymbol?: return@analyze null - val translator = DokkaSymbolVisitor(sourceSet, sourceSet.displayName, kotlinAnalysis, logger = context.logger) - - val parentDRI = symbol.getContainingSymbol()?.let { getDRIFromSymbol(it) } ?: /* top level */ DRI(dri.packageName) - with(translator) { - return@analyze visitNamedClassOrObjectSymbol(symbol, parentDRI) - } - } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolFullClassHierarchyBuilder.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolFullClassHierarchyBuilder.kt deleted file mode 100644 index 0b68ac81..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolFullClassHierarchyBuilder.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.psi.PsiClass -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource -import org.jetbrains.dokka.analysis.java.util.from -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getDRIFromClassLike -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.* -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.types.KtType -import org.jetbrains.dokka.analysis.kotlin.internal.ClassHierarchy -import org.jetbrains.dokka.analysis.kotlin.internal.FullClassHierarchyBuilder -import org.jetbrains.dokka.analysis.kotlin.internal.Supertypes -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.AnnotationTranslator -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.TypeTranslator -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.kotlin.psi.KtClassOrObject -import java.util.concurrent.ConcurrentHashMap - - -internal class SymbolFullClassHierarchyBuilder(context: DokkaContext) : FullClassHierarchyBuilder { - private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - - override suspend fun build(module: DModule): ClassHierarchy { - val map = module.sourceSets.associateWith { ConcurrentHashMap<DRI, List<DRI>>() } - module.packages.forEach { visitDocumentable(it, map) } - return map - } - - private fun KtAnalysisSession.collectSupertypesFromKtType( - driWithKType: Pair<DRI, KtType>, - supersMap: MutableMap<DRI, Supertypes> - ) { - val (dri, kotlinType) = driWithKType - if (supersMap[dri] == null) { - val supertypes = kotlinType.getDirectSuperTypes(shouldApproximate = true).filterNot { it.isAny } - val supertypesDriWithKType = supertypes.mapNotNull { supertype -> - supertype.expandedClassSymbol?.let { - getDRIFromClassLike(it) to supertype - } - } - supersMap[dri] = supertypesDriWithKType.map { it.first } - supertypesDriWithKType.forEach { collectSupertypesFromKtType(it, supersMap) } - } - } - - private fun collectSupertypesFromPsiClass( - driWithPsiClass: Pair<DRI, PsiClass>, - supersMap: MutableMap<DRI, Supertypes> - ) { - val (dri, psiClass) = driWithPsiClass - val supertypes = psiClass.superTypes.mapNotNull { it.resolve() } - .filterNot { it.qualifiedName == "java.lang.Object" } - val supertypesDriWithPsiClass = supertypes.map { DRI.from(it) to it } - - if (supersMap[dri] == null) { - supersMap[dri] = supertypesDriWithPsiClass.map { it.first } - supertypesDriWithPsiClass.forEach { collectSupertypesFromPsiClass(it, supersMap) } - } - } - - private fun visitDocumentable( - documentable: Documentable, - hierarchy: SourceSetDependent<MutableMap<DRI, List<DRI>>> - ) { - if (documentable is WithScope) { - documentable.classlikes.forEach { visitDocumentable(it, hierarchy) } - } - if (documentable is DClasslike) { - // to build a full class graph, - // using supertypes from Documentable is not enough since it keeps only one level of hierarchy - documentable.sources.forEach { (sourceSet, source) -> - if (source is KtPsiDocumentableSource) { - (source.psi as? KtClassOrObject)?.let { psi -> - analyze(kotlinAnalysis.getModule(sourceSet)) { - val type = psi.getNamedClassOrObjectSymbol()?.buildSelfClassType() ?: return@analyze - hierarchy[sourceSet]?.let { collectSupertypesFromKtType(documentable.dri to type, it) } - } - } - } else if (source is PsiDocumentableSource) { - val psi = source.psi as PsiClass - hierarchy[sourceSet]?.let { collectSupertypesFromPsiClass(documentable.dri to psi, it) } - } - } - } - } - - internal class SuperclassesWithKind( - val typeConstructorWithKind: TypeConstructorWithKind, - val superclasses: List<TypeConstructorWithKind> - ) - - /** - * Currently, it works only for Symbols - */ - internal fun collectKotlinSupertypesWithKind( - documentable: Iterable<Documentable>, - sourceSet: DokkaConfiguration.DokkaSourceSet - ): Map<DRI, SuperclassesWithKind> { - val typeTranslator = TypeTranslator(sourceSet, AnnotationTranslator()) - val hierarchy = mutableMapOf<DRI, SuperclassesWithKind>() - - analyze(kotlinAnalysis.getModule(sourceSet)) { - documentable.filterIsInstance<DClasslike>().forEach { - val source = it.sources[sourceSet] - if (source is KtPsiDocumentableSource) { - (source.psi as? KtClassOrObject)?.let { psi -> - val type = psi.getNamedClassOrObjectSymbol()?.buildSelfClassType() ?: return@analyze - collectSupertypesWithKindFromKtType(typeTranslator, with(typeTranslator) { - toTypeConstructorWithKindFrom(type) - } to type, hierarchy) - } - } // else if (source is PsiDocumentableSource) TODO val psi = source.psi as? PsiClass - } - } - return hierarchy - } - - private fun KtAnalysisSession.collectSupertypesWithKindFromKtType( - typeTranslator: TypeTranslator, - typeConstructorWithKindWithKType: Pair<TypeConstructorWithKind, KtType>, - supersMap: MutableMap<DRI, SuperclassesWithKind> - ) { - val (typeConstructorWithKind, kotlinType) = typeConstructorWithKindWithKType - - if (supersMap[typeConstructorWithKind.typeConstructor.dri] == null) { - val supertypes = kotlinType.getDirectSuperTypes(shouldApproximate = true).filterNot { it.isAny } - - val supertypesDriWithKType = supertypes.map { supertype -> - with(typeTranslator) { - toTypeConstructorWithKindFrom(supertype) - } to supertype - } - supersMap[typeConstructorWithKind.typeConstructor.dri] = - SuperclassesWithKind(typeConstructorWithKind, supertypesDriWithKType.map { it.first }) - supertypesDriWithKType.forEach { collectSupertypesWithKindFromKtType(typeTranslator, it, supersMap) } - } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolInheritanceBuilder.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolInheritanceBuilder.kt deleted file mode 100644 index 540f08a7..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolInheritanceBuilder.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.psi.PsiClass -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.java.util.from -import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.analysis.kotlin.internal.InheritanceBuilder -import org.jetbrains.dokka.analysis.kotlin.internal.InheritanceNode -import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle - -/** - * This is copy-pasted from org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.DescriptorInheritanceBuilder and adapted for symbols - */ -internal class SymbolInheritanceBuilder(context: DokkaContext) : InheritanceBuilder { - private val symbolFullClassHierarchyBuilder = - context.plugin<InternalKotlinAnalysisPlugin>().querySingle { fullClassHierarchyBuilder } - - override fun build(documentables: Map<DRI, Documentable>): List<InheritanceNode> { - - // this statement is copy-pasted from the version for Descriptors - val psiInheritanceTree = - documentables.flatMap { (_, v) -> (v as? WithSources)?.sources?.values.orEmpty() } - .filterIsInstance<PsiDocumentableSource>().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 - ) - - } - - // copy-pasted from stdlib 1.5 - fun <T, R : Any> Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R? { - for (element in this) { - val result = transform(element) - if (result != null) { - return result - } - } - return null - } - - val jvmSourceSet = - documentables.values.firstNotNullOfOrNull { it.sourceSets.find { it.analysisPlatform == Platform.jvm } } - if (jvmSourceSet == null) - return psiInheritanceTree - - val typeConstructorsMap = - (symbolFullClassHierarchyBuilder as? SymbolFullClassHierarchyBuilder)?.collectKotlinSupertypesWithKind( - documentables.values, - jvmSourceSet - ) - ?: throw IllegalStateException("Unexpected symbolFullClassHierarchyBuildertype") // TODO: https://github.com/Kotlin/dokka/issues/3225 Unify FullClassHierarchyBuilder and InheritanceBuilder into one builder - - fun ClassKind.isInterface() = this == KotlinClassKindTypes.INTERFACE || this == JavaClassKindTypes.INTERFACE - val symbolsInheritanceTree = typeConstructorsMap.map { (dri, superclasses) -> - InheritanceNode( - dri, - superclasses.superclasses.map { InheritanceNode(it.typeConstructor.dri) }, - superclasses.superclasses.filter { it.kind.isInterface() }.map { it.typeConstructor.dri }, - isInterface = superclasses.typeConstructorWithKind.kind.isInterface() - ) - } - - return psiInheritanceTree + symbolsInheritanceTree - } - - private fun gatherPsiClasses(psi: PsiClass): List<Pair<PsiClass, List<PsiClass>>> = psi.supers.toList().let { l -> - listOf(psi to l) + l.flatMap { gatherPsiClasses(it) } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolKotlinToJavaMapper.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolKotlinToJavaMapper.kt deleted file mode 100644 index 77ede87f..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolKotlinToJavaMapper.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.PointingToDeclaration -import org.jetbrains.dokka.analysis.kotlin.internal.KotlinToJavaService -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap // or import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap see https://github.com/Kotlin/dokka/issues/3226 -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName - -/** - * This is copy-pasted from org.jetbrains.dokka.analysis.kotlin.descriptors.compiler.impl.DescriptorKotlinToJavaMapper - */ -internal class SymbolKotlinToJavaMapper : KotlinToJavaService { - - 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/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSyntheticDocumentableDetector.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSyntheticDocumentableDetector.kt deleted file mode 100644 index d281e9c0..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSyntheticDocumentableDetector.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.services - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.util.PsiDocumentableSource -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.model.InheritedMember -import org.jetbrains.dokka.model.WithSources -import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.dokka.analysis.kotlin.internal.SyntheticDocumentableDetector - -internal class SymbolSyntheticDocumentableDetector : SyntheticDocumentableDetector { - - /** - * Currently, it's used only for [org.jetbrains.dokka.base.transformers.documentables.ReportUndocumentedTransformer] - * - * For so-called fake-ovveride declarations - we have [InheritedMember] extra. - * For synthesized declaration - we do not have PSI source. - * - * @see org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin.SOURCE_MEMBER_GENERATED - */ - override fun isSynthetic(documentable: Documentable, sourceSet: DokkaConfiguration.DokkaSourceSet): Boolean { - @Suppress("UNCHECKED_CAST") - val extra = (documentable as? WithExtraProperties<Documentable>)?.extra - val isInherited = extra?.get(InheritedMember)?.inheritedFrom?.get(sourceSet) != null - // TODO the same for JAVA? - val isSynthesized = documentable.getPsi(sourceSet) == null - return isInherited || isSynthesized - } - - private fun Documentable.getPsi(sourceSet: DokkaConfiguration.DokkaSourceSet): PsiElement? { - val documentableSource = (this as? WithSources)?.sources?.get(sourceSet) ?: return null - return when (documentableSource) { - is PsiDocumentableSource -> documentableSource.psi - is KtPsiDocumentableSource -> documentableSource.psi - else -> error("Unknown language sources: ${documentableSource::class}") - } - } - - -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/AnnotationTranslator.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/AnnotationTranslator.kt deleted file mode 100644 index c9882487..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/AnnotationTranslator.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.withEnumEntryExtra -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.ClassValue -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.annotations.* -import org.jetbrains.kotlin.analysis.api.base.KtConstantValue -import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin -import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtFile - -/** - * Map [KtAnnotationApplication] to Dokka [Annotations.Annotation] - */ -internal class AnnotationTranslator { - private fun KtAnalysisSession.getFileLevelAnnotationsFrom(symbol: KtSymbol) = - if (symbol.origin != KtSymbolOrigin.SOURCE) - null - else - (symbol.psi?.containingFile as? KtFile)?.getFileSymbol()?.annotations - ?.map { toDokkaAnnotation(it) } - - private fun KtAnalysisSession.getDirectAnnotationsFrom(annotated: KtAnnotated) = - annotated.annotations.map { toDokkaAnnotation(it) } - - /** - * The examples of annotations from backing field are [JvmField], [JvmSynthetic]. - * - * @return direct annotations, annotations from backing field and file-level annotations - */ - fun KtAnalysisSession.getAllAnnotationsFrom(annotated: KtAnnotated): List<Annotations.Annotation> { - val directAnnotations = getDirectAnnotationsFrom(annotated) - val backingFieldAnnotations = - (annotated as? KtPropertySymbol)?.backingFieldSymbol?.let { getDirectAnnotationsFrom(it) }.orEmpty() - val fileLevelAnnotations = (annotated as? KtSymbol)?.let { getFileLevelAnnotationsFrom(it) }.orEmpty() - return directAnnotations + backingFieldAnnotations + fileLevelAnnotations - } - - private fun KtAnnotationApplication.isNoExistedInSource() = psi == null - private fun AnnotationUseSiteTarget.toDokkaAnnotationScope(): Annotations.AnnotationScope = when (this) { - AnnotationUseSiteTarget.PROPERTY_GETTER -> Annotations.AnnotationScope.DIRECT // due to compatibility with Dokka K1 - AnnotationUseSiteTarget.PROPERTY_SETTER -> Annotations.AnnotationScope.DIRECT // due to compatibility with Dokka K1 - AnnotationUseSiteTarget.FILE -> Annotations.AnnotationScope.FILE - else -> Annotations.AnnotationScope.DIRECT - } - - private fun KtAnalysisSession.mustBeDocumented(annotationApplication: KtAnnotationApplication): Boolean { - if (annotationApplication.isNoExistedInSource()) return false - val annotationClass = getClassOrObjectSymbolByClassId(annotationApplication.classId ?: return false) - return annotationClass?.hasAnnotation(mustBeDocumentedAnnotation) - ?: false - } - - private fun KtAnalysisSession.toDokkaAnnotation(annotationApplication: KtAnnotationApplication) = - Annotations.Annotation( - dri = annotationApplication.classId?.createDRI() - ?: DRI(packageName = "", classNames = ERROR_CLASS_NAME), // classId might be null on a non-existing annotation call, - params = if (annotationApplication is KtAnnotationApplicationWithArgumentsInfo) annotationApplication.arguments.associate { - it.name.asString() to toDokkaAnnotationValue( - it.expression - ) - } else emptyMap(), - mustBeDocumented = mustBeDocumented(annotationApplication), - scope = annotationApplication.useSiteTarget?.toDokkaAnnotationScope() ?: Annotations.AnnotationScope.DIRECT - ) - - @OptIn(ExperimentalUnsignedTypes::class) - private fun KtAnalysisSession.toDokkaAnnotationValue(annotationValue: KtAnnotationValue): AnnotationParameterValue = - when (annotationValue) { - is KtConstantAnnotationValue -> { - when (val value = annotationValue.constantValue) { - is KtConstantValue.KtNullConstantValue -> NullValue - is KtConstantValue.KtFloatConstantValue -> FloatValue(value.value) - is KtConstantValue.KtDoubleConstantValue -> DoubleValue(value.value) - is KtConstantValue.KtLongConstantValue -> LongValue(value.value) - is KtConstantValue.KtIntConstantValue -> IntValue(value.value) - is KtConstantValue.KtBooleanConstantValue -> BooleanValue(value.value) - is KtConstantValue.KtByteConstantValue -> IntValue(value.value.toInt()) - is KtConstantValue.KtCharConstantValue -> StringValue(value.value.toString()) - is KtConstantValue.KtErrorConstantValue -> StringValue(value.renderAsKotlinConstant()) - is KtConstantValue.KtShortConstantValue -> IntValue(value.value.toInt()) - is KtConstantValue.KtStringConstantValue -> StringValue(value.value) - is KtConstantValue.KtUnsignedByteConstantValue -> IntValue(value.value.toInt()) - is KtConstantValue.KtUnsignedIntConstantValue -> IntValue(value.value.toInt()) - is KtConstantValue.KtUnsignedLongConstantValue -> LongValue(value.value.toLong()) - is KtConstantValue.KtUnsignedShortConstantValue -> IntValue(value.value.toInt()) - } - } - - is KtEnumEntryAnnotationValue -> EnumValue( - with(annotationValue.callableId) { this?.className?.asString() + "." + this?.callableName?.asString() }, - getDRIFrom(annotationValue) - ) - - is KtArrayAnnotationValue -> ArrayValue(annotationValue.values.map { toDokkaAnnotationValue(it) }) - is KtAnnotationApplicationValue -> AnnotationValue(toDokkaAnnotation(annotationValue.annotationValue)) - is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> ClassValue( - annotationValue.classId.relativeClassName.asString(), - annotationValue.classId.createDRI() - ) - - is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> throw IllegalStateException("Unexpected a local class in annotation") - is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> ClassValue( - annotationValue.unresolvedQualifierName ?: "", - DRI(packageName = "", classNames = ERROR_CLASS_NAME) - ) - - KtUnsupportedAnnotationValue -> ClassValue( - "<Unsupported Annotation Value>", - DRI(packageName = "", classNames = ERROR_CLASS_NAME) - ) - } - - private fun getDRIFrom(enumEntry: KtEnumEntryAnnotationValue): DRI { - val callableId = - enumEntry.callableId ?: throw IllegalStateException("Can't get `callableId` for enum entry from annotation") - return DRI( - packageName = callableId.packageName.asString(), - classNames = callableId.className?.asString() + "." + callableId.callableName.asString(), - ).withEnumEntryExtra() - } - - companion object { - val mustBeDocumentedAnnotation = ClassId(FqName("kotlin.annotation"), FqName("MustBeDocumented"), false) - private val parameterNameAnnotation = ClassId(FqName("kotlin"), FqName("ParameterName"), false) - - /** - * Functional types can have **generated** [ParameterName] annotation - * @see ParameterName - */ - internal fun KtAnnotated.getPresentableName(): String? = - this.annotationsByClassId(parameterNameAnnotation) - .firstOrNull()?.arguments?.firstOrNull { it.name == Name.identifier("name") }?.expression?.let { it as? KtConstantAnnotationValue } - ?.let { it.constantValue.value.toString() } - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt deleted file mode 100644 index a2cb423a..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - -import org.jetbrains.dokka.links.* -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.symbols.* -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithTypeParameters -import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType -import org.jetbrains.kotlin.name.CallableId -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName - -internal fun ClassId.createDRI(): DRI = DRI( - packageName = this.packageFqName.asString(), classNames = this.relativeClassName.asString() -) - -private fun CallableId.createDRI(receiver: TypeReference?, params: List<TypeReference>): DRI = DRI( - packageName = this.packageName.asString(), - classNames = this.className?.asString(), - callable = Callable( - this.callableName.asString(), - params = params, - receiver = receiver - ) -) - -internal fun getDRIFromNonErrorClassType(nonErrorClassType: KtNonErrorClassType): DRI = - nonErrorClassType.classId.createDRI() - -private val KtCallableSymbol.callableId - get() = this.callableIdIfNonLocal ?: throw IllegalStateException("Can not get callable Id due to it is local") - -// because of compatibility with Dokka K1, DRI of entry is kept as non-callable -internal fun getDRIFromEnumEntry(symbol: KtEnumEntrySymbol): DRI = - symbol.callableId.let { - DRI( - packageName = it.packageName.asString(), - classNames = it.className?.asString() + "." + it.callableName.asString(), - ) - }.withEnumEntryExtra() - - -internal fun KtAnalysisSession.getDRIFromTypeParameter(symbol: KtTypeParameterSymbol): DRI { - val containingSymbol = - (symbol.getContainingSymbol() as? KtSymbolWithTypeParameters) - ?: throw IllegalStateException("Containing symbol is null for type parameter") - val typeParameters = containingSymbol.typeParameters - val index = typeParameters.indexOfFirst { symbol.name == it.name } - return getDRIFromSymbol(containingSymbol).copy(target = PointingToGenericParameters(index)) -} - -internal fun KtAnalysisSession.getDRIFromConstructor(symbol: KtConstructorSymbol): DRI = - (symbol.containingClassIdIfNonLocal - ?: throw IllegalStateException("Can not get class Id due to it is local")).createDRI().copy( - callable = Callable( - name = symbol.containingClassIdIfNonLocal?.relativeClassName?.asString() ?: "", - params = symbol.valueParameters.map { getTypeReferenceFrom(it.returnType) }) - ) - -internal fun KtAnalysisSession.getDRIFromVariableLike(symbol: KtVariableLikeSymbol): DRI { - val receiver = symbol.receiverType?.let { - getTypeReferenceFrom(it) - } - return symbol.callableId.createDRI(receiver, emptyList()) -} - -internal fun KtAnalysisSession.getDRIFromFunctionLike(symbol: KtFunctionLikeSymbol): DRI { - val params = symbol.valueParameters.map { getTypeReferenceFrom(it.returnType) } - val receiver = symbol.receiverType?.let { - getTypeReferenceFrom(it) - } - return symbol.callableIdIfNonLocal?.createDRI(receiver, params) - ?: getDRIFromLocalFunction(symbol) -} - -internal fun getDRIFromClassLike(symbol: KtClassLikeSymbol): DRI = - symbol.classIdIfNonLocal?.createDRI() ?: throw IllegalStateException("Can not get class Id due to it is local") - -internal fun getDRIFromPackage(symbol: KtPackageSymbol): DRI = - DRI(packageName = symbol.fqName.asString()) - -internal fun KtAnalysisSession.getDRIFromValueParameter(symbol: KtValueParameterSymbol): DRI { - val function = (symbol.getContainingSymbol() as? KtFunctionLikeSymbol) - ?: throw IllegalStateException("Containing symbol is null for type parameter") - val index = function.valueParameters.indexOfFirst { it.name == symbol.name } - val funDRI = getDRIFromFunctionLike(function) - return funDRI.copy(target = PointingToCallableParameters(index)) -} - -internal fun KtAnalysisSession.getDRIFromSymbol(symbol: KtSymbol): DRI = - when (symbol) { - is KtEnumEntrySymbol -> getDRIFromEnumEntry(symbol) - is KtTypeParameterSymbol -> getDRIFromTypeParameter(symbol) - is KtConstructorSymbol -> getDRIFromConstructor(symbol) - is KtValueParameterSymbol -> getDRIFromValueParameter(symbol) - is KtVariableLikeSymbol -> getDRIFromVariableLike(symbol) - is KtFunctionLikeSymbol -> getDRIFromFunctionLike(symbol) - is KtClassLikeSymbol -> getDRIFromClassLike(symbol) - is KtPackageSymbol -> getDRIFromPackage(symbol) - else -> throw IllegalStateException("Unknown symbol while creating DRI $symbol") - } - -private fun KtAnalysisSession.getDRIFromNonCallablePossibleLocalSymbol(symbol: KtSymbol): DRI { - if ((symbol as? KtSymbolWithKind)?.symbolKind == KtSymbolKind.LOCAL) { - return symbol.getContainingSymbol()?.let { getDRIFromNonCallablePossibleLocalSymbol(it) } - ?: throw IllegalStateException("Can't get containing symbol for local symbol") - } - return getDRIFromSymbol(symbol) -} - -/** - * Currently, it's used only for functions from enum entry, - * For its members: `memberSymbol.callableIdIfNonLocal=null` - */ -private fun KtAnalysisSession.getDRIFromLocalFunction(symbol: KtFunctionLikeSymbol): DRI { - /** - * A function is inside local object - */ - val containingSymbolDRI = symbol.getContainingSymbol()?.let { getDRIFromNonCallablePossibleLocalSymbol(it) } - ?: throw IllegalStateException("Can't get containing symbol for local function") - return containingSymbolDRI.copy( - callable = Callable( - (symbol as? KtNamedSymbol)?.name?.asString() ?: "", - params = symbol.valueParameters.map { getTypeReferenceFrom(it.returnType) }, - receiver = symbol.receiverType?.let { - getTypeReferenceFrom(it) - } - ) - ) -} - -// ----------- DRI => compiler identifiers ---------------------------------------------------------------------------- -internal fun getClassIdFromDRI(dri: DRI) = ClassId( - FqName(dri.packageName ?: ""), - FqName(dri.classNames ?: throw IllegalStateException("DRI must have `classNames` to get ClassID")), - false -) - diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt deleted file mode 100644 index 298d0182..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - - -import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.* -import com.intellij.psi.util.PsiLiteralUtil -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.java.JavaAnalysisPlugin -import org.jetbrains.dokka.analysis.java.parsers.JavadocParser -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.getGeneratedKDocDocumentationFrom -import org.jetbrains.dokka.analysis.kotlin.symbols.services.KtPsiDocumentableSource -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.getJavaDocDocumentationFrom -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.getKDocDocumentationFrom -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.hasGeneratedKDocDocumentation -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.AnnotationTranslator.Companion.getPresentableName -import org.jetbrains.dokka.analysis.kotlin.symbols.utils.typeConstructorsBeingExceptions -import org.jetbrains.dokka.links.* -import org.jetbrains.dokka.links.Callable -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Visibility -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 -import org.jetbrains.kotlin.KtNodeTypes -import org.jetbrains.kotlin.analysis.api.* -import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotated -import org.jetbrains.kotlin.analysis.api.symbols.* -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility -import org.jetbrains.kotlin.analysis.api.types.* -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.descriptors.java.JavaVisibilities -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier -import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier -import java.nio.file.Paths - -internal class DefaultSymbolToDocumentableTranslator(context: DokkaContext) : AsyncSourceToDocumentableTranslator { - private val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis } - private val javadocParser = JavadocParser( - docCommentParsers = context.plugin<JavaAnalysisPlugin>().query { docCommentParsers }, - docCommentFinder = context.plugin<JavaAnalysisPlugin>().docCommentFinder - ) - - override suspend fun invokeSuspending( - sourceSet: DokkaConfiguration.DokkaSourceSet, - context: DokkaContext - ): DModule { - val analysisContext = kotlinAnalysis - @Suppress("unused") - return DokkaSymbolVisitor( - sourceSet = sourceSet, - moduleName = context.configuration.moduleName, - analysisContext = analysisContext, - logger = context.logger, - javadocParser = javadocParser - ).visitModule() - } -} - -internal fun <T : Bound> T.wrapWithVariance(variance: org.jetbrains.kotlin.types.Variance) = - when (variance) { - org.jetbrains.kotlin.types.Variance.INVARIANT -> Invariance(this) - org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Contravariance(this) - org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Covariance(this) - } - -/** - * Maps [KtSymbol] to Documentable model [Documentable] - */ -internal class DokkaSymbolVisitor( - private val sourceSet: DokkaConfiguration.DokkaSourceSet, - private val moduleName: String, - private val analysisContext: KotlinAnalysis, - private val logger: DokkaLogger, - private val javadocParser: JavadocParser? = null -) { - private var annotationTranslator = AnnotationTranslator() - private var typeTranslator = TypeTranslator(sourceSet, annotationTranslator) - - /** - * To avoid recursive classes - * e.g. - * open class Klass() { - * object Default : Klass() - * } - */ - private val visitedNamedClassOrObjectSymbol: MutableSet<ClassId> = - mutableSetOf() - - private fun <T> T.toSourceSetDependent() = if (this != null) mapOf(sourceSet to this) else emptyMap() - - // KT-54846 will replace - private val KtDeclarationSymbol.isActual - get() = (psi as? KtModifierListOwner)?.hasActualModifier() == true - private val KtDeclarationSymbol.isExpect - get() = (psi as? KtModifierListOwner)?.hasExpectModifier() == true - - private fun <T : KtSymbol> Collection<T>.filterSymbolsInSourceSet() = filter { - it.psi?.containingFile?.virtualFile?.path?.let { path -> - path.isNotBlank() && sourceSet.sourceRoots.any { root -> - Paths.get(path).startsWith(root.toPath()) - } - } == true - } - - fun visitModule(): DModule { - val sourceModule = analysisContext.getModule(sourceSet) - val ktFiles = analysisContext.modulesWithFiles[sourceModule]?.filterIsInstance<KtFile>() ?: throw IllegalStateException("No source files for a source module ${sourceModule.moduleName} of source set ${sourceSet.sourceSetID}") - val processedPackages: MutableSet<FqName> = mutableSetOf() - return analyze(sourceModule) { - val packageSymbols: List<DPackage> = ktFiles - .mapNotNull { - if (processedPackages.contains(it.packageFqName)) - return@mapNotNull null - processedPackages.add(it.packageFqName) - getPackageSymbolIfPackageExists(it.packageFqName)?.let { it1 -> - visitPackageSymbol( - it1 - ) - } - } - - DModule( - name = moduleName, - packages = packageSymbols, - documentation = emptyMap(), - expectPresentInSet = null, - sourceSets = setOf(sourceSet) - ) - } - } - - private fun KtAnalysisSession.visitPackageSymbol(packageSymbol: KtPackageSymbol): DPackage { - val dri = getDRIFromPackage(packageSymbol) - val scope = packageSymbol.getPackageScope() - val callables = scope.getCallableSymbols().toList().filterSymbolsInSourceSet() - val classifiers = scope.getClassifierSymbols().toList().filterSymbolsInSourceSet() - - val functions = callables.filterIsInstance<KtFunctionSymbol>().map { visitFunctionSymbol(it, dri) } - val properties = callables.filterIsInstance<KtPropertySymbol>().map { visitPropertySymbol(it, dri) } - val classlikes = - classifiers.filterIsInstance<KtNamedClassOrObjectSymbol>() - .map { visitNamedClassOrObjectSymbol(it, dri) } - val typealiases = classifiers.filterIsInstance<KtTypeAliasSymbol>().map { visitTypeAliasSymbol(it, dri) } - - return DPackage( - dri = dri, - functions = functions, - properties = properties, - classlikes = classlikes, - typealiases = typealiases, - documentation = emptyMap(), - sourceSets = setOf(sourceSet) - ) - } - - private fun KtAnalysisSession.visitTypeAliasSymbol( - typeAliasSymbol: KtTypeAliasSymbol, - parent: DRI - ): DTypeAlias = withExceptionCatcher(typeAliasSymbol) { - val name = typeAliasSymbol.name.asString() - val dri = parent.withClass(name) - - val ancestryInfo = with(typeTranslator) { buildAncestryInformationFrom(typeAliasSymbol.expandedType) } - - val generics = - typeAliasSymbol.typeParameters.mapIndexed { index, symbol -> visitVariantTypeParameter(index, symbol, dri) } - - return DTypeAlias( - dri = dri, - name = name, - type = GenericTypeConstructor( - dri = dri, - projections = generics.map { it.variantTypeParameter }), // this property can be removed in DTypeAlias - expectPresentInSet = null, - underlyingType = toBoundFrom(typeAliasSymbol.expandedType).toSourceSetDependent(), - visibility = typeAliasSymbol.getDokkaVisibility().toSourceSetDependent(), - documentation = getDocumentation(typeAliasSymbol)?.toSourceSetDependent() ?: emptyMap(), - sourceSets = setOf(sourceSet), - generics = generics, - sources = typeAliasSymbol.getSource(), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(typeAliasSymbol)?.toSourceSetDependent()?.toAnnotations(), - ancestryInfo.exceptionInSupertypesOrNull(), - ) - ) - } - - fun KtAnalysisSession.visitNamedClassOrObjectSymbol( - namedClassOrObjectSymbol: KtNamedClassOrObjectSymbol, - parent: DRI - ): DClasslike = withExceptionCatcher(namedClassOrObjectSymbol) { - namedClassOrObjectSymbol.classIdIfNonLocal?.let { visitedNamedClassOrObjectSymbol.add(it) } - - val name = namedClassOrObjectSymbol.name.asString() - val dri = parent.withClass(name) - - val isExpect = namedClassOrObjectSymbol.isExpect - val isActual = namedClassOrObjectSymbol.isActual - val documentation = getDocumentation(namedClassOrObjectSymbol)?.toSourceSetDependent() ?: emptyMap() - - val (constructors, functions, properties, classlikesWithoutCompanion) = getDokkaScopeFrom(namedClassOrObjectSymbol, dri) - - val companionObject = namedClassOrObjectSymbol.companionObject?.let { - visitNamedClassOrObjectSymbol( - it, - dri - ) - } as? DObject - val classlikes = if (companionObject == null) classlikesWithoutCompanion else classlikesWithoutCompanion + companionObject - - val generics = namedClassOrObjectSymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - val ancestryInfo = - with(typeTranslator) { buildAncestryInformationFrom(namedClassOrObjectSymbol.buildSelfClassType()) } - val supertypes = - //(ancestryInfo.interfaces.map{ it.typeConstructor } + listOfNotNull(ancestryInfo.superclass?.typeConstructor)) - namedClassOrObjectSymbol.superTypes.filterNot { it.isAny } - .map { with(typeTranslator) { toTypeConstructorWithKindFrom(it) } } - .toSourceSetDependent() - return@withExceptionCatcher when (namedClassOrObjectSymbol.classKind) { - KtClassKind.OBJECT, KtClassKind.COMPANION_OBJECT -> - DObject( - dri = dri, - name = name, - functions = functions, - properties = properties, - classlikes = classlikes, - sources = namedClassOrObjectSymbol.getSource(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = namedClassOrObjectSymbol.getDokkaVisibility().toSourceSetDependent(), - supertypes = supertypes, - documentation = documentation, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - namedClassOrObjectSymbol.additionalExtras()?.toSourceSetDependent() - ?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(namedClassOrObjectSymbol)?.toSourceSetDependent()?.toAnnotations(), - ImplementedInterfaces(ancestryInfo.allImplementedInterfaces().toSourceSetDependent()), - ancestryInfo.exceptionInSupertypesOrNull() - ) - ) - - KtClassKind.CLASS -> DClass( - dri = dri, - name = name, - constructors = constructors, - functions = functions, - properties = properties, - classlikes = classlikes, - sources = namedClassOrObjectSymbol.getSource(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = namedClassOrObjectSymbol.getDokkaVisibility().toSourceSetDependent(), - supertypes = supertypes, - generics = generics, - documentation = documentation, - modifier = namedClassOrObjectSymbol.getDokkaModality().toSourceSetDependent(), - companion = companionObject, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - namedClassOrObjectSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(namedClassOrObjectSymbol)?.toSourceSetDependent()?.toAnnotations(), - ImplementedInterfaces(ancestryInfo.allImplementedInterfaces().toSourceSetDependent()), - ancestryInfo.exceptionInSupertypesOrNull() - ) - ) - - KtClassKind.INTERFACE -> DInterface( - dri = dri, - name = name, - functions = functions, - properties = properties, - classlikes = classlikes, - sources = namedClassOrObjectSymbol.getSource(), // - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = namedClassOrObjectSymbol.getDokkaVisibility().toSourceSetDependent(), - supertypes = supertypes, - generics = generics, - documentation = documentation, - companion = companionObject, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - namedClassOrObjectSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(namedClassOrObjectSymbol)?.toSourceSetDependent()?.toAnnotations(), - ImplementedInterfaces(ancestryInfo.allImplementedInterfaces().toSourceSetDependent()), - ancestryInfo.exceptionInSupertypesOrNull() - ) - ) - - KtClassKind.ANNOTATION_CLASS -> DAnnotation( - dri = dri, - name = name, - documentation = documentation, - functions = functions, - properties = properties, - classlikes = classlikes, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - companion = companionObject, - visibility = namedClassOrObjectSymbol.getDokkaVisibility().toSourceSetDependent(), - generics = generics, - constructors = constructors, - sources = namedClassOrObjectSymbol.getSource(), - extra = PropertyContainer.withAll( - namedClassOrObjectSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(namedClassOrObjectSymbol)?.toSourceSetDependent()?.toAnnotations(), - ) - ) - - KtClassKind.ANONYMOUS_OBJECT -> throw NotImplementedError("ANONYMOUS_OBJECT does not support") - KtClassKind.ENUM_CLASS -> { - /** - * See https://github.com/Kotlin/dokka/issues/3129 - * - * e.g. the `A` enum entry in the `enum E` is - * ``` - * static val A: E = object : E() { - * val x: Int = 5 - * } - * ``` - * it needs to exclude all static members like `values` and `valueOf` from the enum class's scope - */ - val enumEntryScope = lazy { - getDokkaScopeFrom(namedClassOrObjectSymbol, dri, includeStaticScope = false).let { - it.copy( - functions = it.functions.map { it.withNewExtras( it.extra + InheritedMember(dri.copy(callable = null).toSourceSetDependent())) }, - properties = it.properties.map { it.withNewExtras( it.extra + InheritedMember(dri.copy(callable = null).toSourceSetDependent())) } - ) - } - } - - val entries = - namedClassOrObjectSymbol.getEnumEntries().map { - visitEnumEntrySymbol(it, enumEntryScope.value) - } - - DEnum( - dri = dri, - name = name, - entries = entries, - constructors = constructors, - functions = functions, - properties = properties, - classlikes = classlikes, - sources = namedClassOrObjectSymbol.getSource(), - expectPresentInSet = sourceSet.takeIf { isExpect }, - visibility = namedClassOrObjectSymbol.getDokkaVisibility().toSourceSetDependent(), - supertypes = supertypes, - documentation = documentation, - companion = namedClassOrObjectSymbol.companionObject?.let { - visitNamedClassOrObjectSymbol( - it, - dri - ) - } as? DObject, - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - namedClassOrObjectSymbol.additionalExtras()?.toSourceSetDependent() - ?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(namedClassOrObjectSymbol)?.toSourceSetDependent()?.toAnnotations(), - ImplementedInterfaces(ancestryInfo.allImplementedInterfaces().toSourceSetDependent()) - ) - ) - } - } - } - - private data class DokkaScope( - val constructors: List<DFunction>, - val functions: List<DFunction>, - val properties: List<DProperty>, - val classlikesWithoutCompanion: List<DClasslike> - ) - - /** - * @param includeStaticScope flag to add static members, e.g. `valueOf`, `values` and `entries` members for Enum - */ - private fun KtAnalysisSession.getDokkaScopeFrom( - namedClassOrObjectSymbol: KtNamedClassOrObjectSymbol, - dri: DRI, - includeStaticScope: Boolean = true - ): DokkaScope { - // e.g. getStaticMemberScope contains `valueOf`, `values` and `entries` members for Enum - val scope = if(includeStaticScope) listOf(namedClassOrObjectSymbol.getMemberScope(), namedClassOrObjectSymbol.getStaticMemberScope()).asCompositeScope() else namedClassOrObjectSymbol.getMemberScope() - val constructors = scope.getConstructors().map { visitConstructorSymbol(it) }.toList() - - val callables = scope.getCallableSymbols().toList() - val classifiers = scope.getClassifierSymbols().toList() - - val syntheticJavaProperties = - namedClassOrObjectSymbol.buildSelfClassType().getSyntheticJavaPropertiesScope()?.getCallableSignatures() - ?.map { it.symbol } - ?.filterIsInstance<KtSyntheticJavaPropertySymbol>() ?: emptySequence() - - fun List<KtJavaFieldSymbol>.filterOutSyntheticJavaPropBackingField() = - filterNot { javaField -> syntheticJavaProperties.any { it.hasBackingField && javaField.name == it.name } } - - val javaFields = callables.filterIsInstance<KtJavaFieldSymbol>() - .filterOutSyntheticJavaPropBackingField() - - fun List<KtFunctionSymbol>.filterOutSyntheticJavaPropAccessors() = filterNot { fn -> - if (fn.origin == KtSymbolOrigin.JAVA && fn.callableIdIfNonLocal != null) - syntheticJavaProperties.any { fn.callableIdIfNonLocal == it.javaGetterSymbol.callableIdIfNonLocal || fn.callableIdIfNonLocal == it.javaSetterSymbol?.callableIdIfNonLocal } - else false - } - - val functions = callables.filterIsInstance<KtFunctionSymbol>() - .filterOutSyntheticJavaPropAccessors().map { visitFunctionSymbol(it, dri) } - - - val properties = callables.filterIsInstance<KtPropertySymbol>().map { visitPropertySymbol(it, dri) } + - syntheticJavaProperties.map { visitPropertySymbol(it, dri) } + - javaFields.map { visitJavaFieldSymbol(it, dri) } - - - fun List<KtNamedClassOrObjectSymbol>.filterOutCompanion() = - filterNot { - it.classKind == KtClassKind.COMPANION_OBJECT - } - - fun List<KtNamedClassOrObjectSymbol>.filterOutAndMarkAlreadyVisited() = filterNot { symbol -> - visitedNamedClassOrObjectSymbol.contains(symbol.classIdIfNonLocal) - .also { - if (!it) symbol.classIdIfNonLocal?.let { classId -> - visitedNamedClassOrObjectSymbol.add( - classId - ) - } - } - } - - val classlikes = classifiers.filterIsInstance<KtNamedClassOrObjectSymbol>() - .filterOutCompanion() // also, this is a hack to filter out companion for enum - .filterOutAndMarkAlreadyVisited() - .map { visitNamedClassOrObjectSymbol(it, dri) } - - return DokkaScope( - constructors = constructors, - functions = functions, - properties = properties, - classlikesWithoutCompanion = classlikes - ) - } - - private fun KtAnalysisSession.visitEnumEntrySymbol( - enumEntrySymbol: KtEnumEntrySymbol, scope: DokkaScope - ): DEnumEntry = withExceptionCatcher(enumEntrySymbol) { - val dri = getDRIFromEnumEntry(enumEntrySymbol) - val isExpect = false - - return DEnumEntry( - dri = dri, - name = enumEntrySymbol.name.asString(), - documentation = getDocumentation(enumEntrySymbol)?.toSourceSetDependent() ?: emptyMap(), - functions = scope.functions, - properties = scope.properties, - classlikes = emptyList(), // always empty, see https://github.com/Kotlin/dokka/issues/3129 - sourceSets = setOf(sourceSet), - expectPresentInSet = sourceSet.takeIf { isExpect }, - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(enumEntrySymbol)?.toSourceSetDependent()?.toAnnotations() - ) - ) - } - - private fun KtAnalysisSession.visitPropertySymbol(propertySymbol: KtPropertySymbol, parent: DRI): DProperty = - withExceptionCatcher(propertySymbol) { - val dri = createDRIWithOverridden(propertySymbol).origin - val inheritedFrom = dri.getInheritedFromDRI(parent) - val isExpect = propertySymbol.isExpect - val isActual = propertySymbol.isActual - val generics = - propertySymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - return DProperty( - dri = dri, - name = propertySymbol.name.asString(), - receiver = propertySymbol.receiverParameter?.let { - visitReceiverParameter( - it, - dri - ) - }, - sources = propertySymbol.getSource(), - getter = propertySymbol.getter?.let { visitPropertyAccessor(it, propertySymbol, dri) }, - setter = propertySymbol.setter?.let { visitPropertyAccessor(it, propertySymbol, dri) }, - visibility = propertySymbol.visibility.toDokkaVisibility().toSourceSetDependent(), - documentation = getDocumentation(propertySymbol)?.toSourceSetDependent() ?: emptyMap(), // TODO - modifier = propertySymbol.modality.toDokkaModifier().toSourceSetDependent(), - type = toBoundFrom(propertySymbol.returnType), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - generics = generics, - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - propertySymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(propertySymbol)?.toSourceSetDependent()?.toAnnotations(), - propertySymbol.getDefaultValue()?.let { DefaultValue(it.toSourceSetDependent()) }, - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - takeUnless { propertySymbol.isVal }?.let { IsVar }, - takeIf { propertySymbol.psi is KtParameter }?.let { IsAlsoParameter(listOf(sourceSet)) } - ) - ) - } - - private fun KtAnalysisSession.visitJavaFieldSymbol( - javaFieldSymbol: KtJavaFieldSymbol, - parent: DRI - ): DProperty = - withExceptionCatcher(javaFieldSymbol) { - val dri = createDRIWithOverridden(javaFieldSymbol).origin - val inheritedFrom = dri.getInheritedFromDRI(parent) - val isExpect = false - val isActual = false - val generics = - javaFieldSymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - return DProperty( - dri = dri, - name = javaFieldSymbol.name.asString(), - receiver = javaFieldSymbol.receiverParameter?.let { - visitReceiverParameter( - it, - dri - ) - }, - sources = javaFieldSymbol.getSource(), - getter = null, - setter = null, - visibility = javaFieldSymbol.getDokkaVisibility().toSourceSetDependent(), - documentation = getDocumentation(javaFieldSymbol)?.toSourceSetDependent() ?: emptyMap(), // TODO - modifier = javaFieldSymbol.modality.toDokkaModifier().toSourceSetDependent(), - type = toBoundFrom(javaFieldSymbol.returnType), - expectPresentInSet = sourceSet.takeIf { isExpect }, - sourceSets = setOf(sourceSet), - generics = generics, - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - javaFieldSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(javaFieldSymbol)?.toSourceSetDependent()?.toAnnotations(), - //javaFieldSymbol.getDefaultValue()?.let { DefaultValue(it.toSourceSetDependent()) }, - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - // non-final java property should be var - takeUnless { javaFieldSymbol.isVal }?.let { IsVar } - ) - ) - } - - private fun KtAnalysisSession.visitPropertyAccessor( - propertyAccessorSymbol: KtPropertyAccessorSymbol, - propertySymbol: KtPropertySymbol, - propertyDRI: DRI - ): DFunction = withExceptionCatcher(propertyAccessorSymbol) { - val isGetter = propertyAccessorSymbol is KtPropertyGetterSymbol - // it also covers @JvmName annotation - val name = (if (isGetter) propertySymbol.javaGetterName else propertySymbol.javaSetterName)?.asString() ?: "" - - // SyntheticJavaProperty has callableIdIfNonLocal, propertyAccessorSymbol.origin = JAVA_SYNTHETIC_PROPERTY - // For Kotlin properties callableIdIfNonLocal=null - val dri = if (propertyAccessorSymbol.callableIdIfNonLocal != null) - getDRIFromFunctionLike(propertyAccessorSymbol) - else - propertyDRI.copy( - callable = Callable(name, null, propertyAccessorSymbol.valueParameters.map { getTypeReferenceFrom(it.returnType) }) - ) - // for SyntheticJavaProperty - val inheritedFrom = if(propertyAccessorSymbol.origin == KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY) dri.copy(callable = null) else null - - val isExpect = propertyAccessorSymbol.isExpect - val isActual = propertyAccessorSymbol.isActual - - val generics = propertyAccessorSymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - return DFunction( - dri = dri, - name = name, - isConstructor = false, - receiver = propertyAccessorSymbol.receiverParameter?.let { - visitReceiverParameter( - it, - dri - ) - }, - parameters = propertyAccessorSymbol.valueParameters.mapIndexed { index, symbol -> - visitValueParameter(index, symbol, dri) - }, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sources = propertyAccessorSymbol.getSource(), - visibility = propertyAccessorSymbol.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = generics, - documentation = getDocumentation(propertyAccessorSymbol)?.toSourceSetDependent() ?: emptyMap(), - modifier = propertyAccessorSymbol.modality.toDokkaModifier().toSourceSetDependent(), - type = toBoundFrom(propertyAccessorSymbol.returnType), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - propertyAccessorSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - getDokkaAnnotationsFrom(propertyAccessorSymbol)?.toSourceSetDependent()?.toAnnotations() - ) - ) - } - - private fun KtAnalysisSession.visitConstructorSymbol( - constructorSymbol: KtConstructorSymbol - ): DFunction = withExceptionCatcher(constructorSymbol) { - val name = constructorSymbol.containingClassIdIfNonLocal?.shortClassName?.asString() - ?: throw IllegalStateException("Unknown containing class of constructor") - val dri = createDRIWithOverridden(constructorSymbol).origin - val isExpect = false // TODO - val isActual = false // TODO - - val generics = constructorSymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - val documentation = getDocumentation(constructorSymbol)?.let { docNode -> - if (constructorSymbol.isPrimary) { - docNode.copy(children = (docNode.children.find { it is Constructor }?.root?.let { constructor -> - listOf(Description(constructor)) - } ?: emptyList<TagWrapper>()) + docNode.children.filterIsInstance<Param>()) - } else { - docNode - } - }?.toSourceSetDependent() - - return DFunction( - dri = dri, - name = name, - isConstructor = true, - receiver = constructorSymbol.receiverParameter?.let { - visitReceiverParameter( - it, - dri - ) - }, - parameters = constructorSymbol.valueParameters.mapIndexed { index, symbol -> - visitValueParameter(index, symbol, dri) - }, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sources = constructorSymbol.getSource(), - visibility = constructorSymbol.visibility.toDokkaVisibility().toSourceSetDependent(), - generics = generics, - documentation = documentation ?: emptyMap(), - modifier = KotlinModifier.Empty.toSourceSetDependent(), - type = toBoundFrom(constructorSymbol.returnType), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(constructorSymbol)?.toSourceSetDependent()?.toAnnotations(), - takeIf { constructorSymbol.isPrimary }?.let { PrimaryConstructorExtra } - ) - ) - } - - private fun KtAnalysisSession.visitFunctionSymbol(functionSymbol: KtFunctionSymbol, parent: DRI): DFunction = - withExceptionCatcher(functionSymbol) { - val dri = createDRIWithOverridden(functionSymbol).origin - val inheritedFrom = dri.getInheritedFromDRI(parent) - val isExpect = functionSymbol.isExpect - val isActual = functionSymbol.isActual - - val generics = - functionSymbol.typeParameters.mapIndexed { index, symbol -> - visitVariantTypeParameter( - index, - symbol, - dri - ) - } - - return DFunction( - dri = dri, - name = functionSymbol.name.asString(), - isConstructor = false, - receiver = functionSymbol.receiverParameter?.let { - visitReceiverParameter( - it, - dri - ) - }, - parameters = functionSymbol.valueParameters.mapIndexed { index, symbol -> - visitValueParameter(index, symbol, dri) - }, - expectPresentInSet = sourceSet.takeIf { isExpect }, - sources = functionSymbol.getSource(), - visibility = functionSymbol.getDokkaVisibility().toSourceSetDependent(), - generics = generics, - documentation = getDocumentation(functionSymbol)?.toSourceSetDependent() ?: emptyMap(), - modifier = functionSymbol.getDokkaModality().toSourceSetDependent(), - type = toBoundFrom(functionSymbol.returnType), - sourceSets = setOf(sourceSet), - isExpectActual = (isExpect || isActual), - extra = PropertyContainer.withAll( - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - functionSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(functionSymbol) - ?.toSourceSetDependent()?.toAnnotations(), - ObviousMember.takeIf { isObvious(functionSymbol) }, - ) - ) - } - - private fun KtAnalysisSession.visitValueParameter( - index: Int, valueParameterSymbol: KtValueParameterSymbol, dri: DRI - ) = DParameter( - dri = dri.copy(target = PointingToCallableParameters(index)), - name = valueParameterSymbol.name.asString(), - type = toBoundFrom(valueParameterSymbol.returnType), - expectPresentInSet = null, - documentation = getDocumentation(valueParameterSymbol)?.toSourceSetDependent() ?: emptyMap(), - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll( - valueParameterSymbol.additionalExtras()?.toSourceSetDependent()?.toAdditionalModifiers(), - getDokkaAnnotationsFrom(valueParameterSymbol)?.toSourceSetDependent()?.toAnnotations(), - valueParameterSymbol.getDefaultValue()?.let { DefaultValue(it.toSourceSetDependent()) } - ) - ) - - private fun KtAnalysisSession.visitReceiverParameter( - receiverParameterSymbol: KtReceiverParameterSymbol, dri: DRI - ) = DParameter( - dri = dri.copy(target = PointingToDeclaration), - name = null, - type = toBoundFrom(receiverParameterSymbol.type), - expectPresentInSet = null, - documentation = getDocumentation(receiverParameterSymbol)?.toSourceSetDependent() ?: emptyMap(), - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(receiverParameterSymbol)?.toSourceSetDependent()?.toAnnotations() - ) - ) - - private fun KtValueParameterSymbol.getDefaultValue(): Expression? = - if (origin == KtSymbolOrigin.SOURCE) (psi as? KtParameter)?.defaultValue?.toDefaultValueExpression() - else null - - private fun KtPropertySymbol.getDefaultValue(): Expression? = - (initializer?.initializerPsi as? KtConstantExpression)?.toDefaultValueExpression() // TODO consider [KtConstantInitializerValue], but should we keep an original format, e.g. 0xff or 0b101? - - private fun KtExpression.toDefaultValueExpression(): Expression? = when (node?.elementType) { - KtNodeTypes.INTEGER_CONSTANT -> PsiLiteralUtil.parseLong(node?.text)?.let { IntegerConstant(it) } - KtNodeTypes.FLOAT_CONSTANT -> if (node?.text?.toLowerCase()?.endsWith('f') == true) - PsiLiteralUtil.parseFloat(node?.text)?.let { FloatConstant(it) } - else PsiLiteralUtil.parseDouble(node?.text)?.let { DoubleConstant(it) } - - KtNodeTypes.BOOLEAN_CONSTANT -> BooleanConstant(node?.text == "true") - KtNodeTypes.STRING_TEMPLATE -> StringConstant(node.findChildByType(KtNodeTypes.LITERAL_STRING_TEMPLATE_ENTRY)?.text.orEmpty()) - else -> node?.text?.let { ComplexExpression(it) } - } - - private fun KtAnalysisSession.visitVariantTypeParameter( - index: Int, - typeParameterSymbol: KtTypeParameterSymbol, - dri: DRI - ): DTypeParameter { - val upperBoundsOrNullableAny = - typeParameterSymbol.upperBounds.takeIf { it.isNotEmpty() } ?: listOf(this.builtinTypes.NULLABLE_ANY) - return DTypeParameter( - variantTypeParameter = TypeParameter( - dri = dri.copy(target = PointingToGenericParameters(index)), - name = typeParameterSymbol.name.asString(), - presentableName = typeParameterSymbol.getPresentableName() - ).wrapWithVariance(typeParameterSymbol.variance), - documentation = getDocumentation(typeParameterSymbol)?.toSourceSetDependent() ?: emptyMap(), - expectPresentInSet = null, - bounds = upperBoundsOrNullableAny.map { toBoundFrom(it) }, - sourceSets = setOf(sourceSet), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(typeParameterSymbol)?.toSourceSetDependent()?.toAnnotations() - ) - ) - } - // ----------- Utils ---------------------------------------------------------------------------- - - private fun KtAnalysisSession.getDokkaAnnotationsFrom(annotated: KtAnnotated): List<Annotations.Annotation>? = - with(annotationTranslator) { getAllAnnotationsFrom(annotated) }.takeUnless { it.isEmpty() } - - private fun KtAnalysisSession.toBoundFrom(type: KtType) = - with(typeTranslator) { toBoundFrom(type) } - - /** - * `createDRI` returns the DRI of the exact element and potential DRI of an element that is overriding it - * (It can be also FAKE_OVERRIDE which is in fact just inheritance of the symbol) - * - * Looking at what PSIs do, they give the DRI of the element within the classnames where it is actually - * declared and inheritedFrom as the same DRI but truncated callable part. - * Therefore, we set callable to null and take the DRI only if it is indeed coming from different class. - */ - private fun DRI.getInheritedFromDRI(dri: DRI): DRI? { - return this.copy(callable = null) - .takeIf { dri.classNames != this.classNames || dri.packageName != this.packageName } - } - - data class DRIWithOverridden(val origin: DRI, val overridden: DRI? = null) - - private fun KtAnalysisSession.createDRIWithOverridden( - callableSymbol: KtCallableSymbol, - wasOverriddenBy: DRI? = null - ): DRIWithOverridden { - if (callableSymbol is KtPropertySymbol && callableSymbol.isOverride - || callableSymbol is KtFunctionSymbol && callableSymbol.isOverride - ) { - return DRIWithOverridden(getDRIFromSymbol(callableSymbol), wasOverriddenBy) - } - - val overriddenSymbols = callableSymbol.getAllOverriddenSymbols() - // For already - return if (overriddenSymbols.isEmpty()) { - DRIWithOverridden(getDRIFromSymbol(callableSymbol), wasOverriddenBy) - } else { - createDRIWithOverridden(overriddenSymbols.first()) - } - } - - private fun KtAnalysisSession.getDocumentation(symbol: KtSymbol) = - if (symbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED) - getGeneratedKDocDocumentationFrom(symbol) - else - getKDocDocumentationFrom(symbol, logger) ?: javadocParser?.let { getJavaDocDocumentationFrom(symbol, it) } - - private fun KtAnalysisSession.isObvious(functionSymbol: KtFunctionSymbol): Boolean { - return functionSymbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED && !hasGeneratedKDocDocumentation(functionSymbol) || - !functionSymbol.isOverride && functionSymbol.callableIdIfNonLocal?.classId?.isObvious() == true - } - - private fun ClassId.isObvious(): Boolean = with(asString()) { - return this == "kotlin/Any" || this == "kotlin/Enum" - || this == "java.lang/Object" || this == "java.lang/Enum" - } - - private fun KtSymbol.getSource() = KtPsiDocumentableSource(psi).toSourceSetDependent() - - private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? = - typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() } - ?.let { ExceptionInSupertypes(it.toSourceSetDependent()) } - - - // ----------- Translators of modifiers ---------------------------------------------------------------------------- - private fun KtSymbolWithModality.getDokkaModality() = modality.toDokkaModifier() - private fun KtSymbolWithVisibility.getDokkaVisibility() = visibility.toDokkaVisibility() - private fun KtValueParameterSymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.NoInline.takeIf { isNoinline }, - ExtraModifiers.KotlinOnlyModifiers.CrossInline.takeIf { isCrossinline }, - ExtraModifiers.KotlinOnlyModifiers.VarArg.takeIf { isVararg } - ).toSet().takeUnless { it.isEmpty() } - - private fun KtPropertyAccessorSymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Inline.takeIf { isInline }, -//ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { isOverride } - ).toSet().takeUnless { it.isEmpty() } - - private fun KtPropertySymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Const.takeIf { (this as? KtKotlinPropertySymbol)?.isConst == true }, - ExtraModifiers.KotlinOnlyModifiers.LateInit.takeIf { (this as? KtKotlinPropertySymbol)?.isLateInit == true }, - //ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - //ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - //ExtraModifiers.KotlinOnlyModifiers.Static.takeIf { isStatic }, - ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { isOverride } - ).toSet().takeUnless { it.isEmpty() } - - private fun KtJavaFieldSymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isStatic } - ).toSet().takeUnless { it.isEmpty() } - - private fun KtFunctionSymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Infix.takeIf { isInfix }, - ExtraModifiers.KotlinOnlyModifiers.Inline.takeIf { isInline }, - ExtraModifiers.KotlinOnlyModifiers.Suspend.takeIf { isSuspend }, - ExtraModifiers.KotlinOnlyModifiers.Operator.takeIf { isOperator }, -//ExtraModifiers.JavaOnlyModifiers.Static.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - ExtraModifiers.KotlinOnlyModifiers.TailRec.takeIf { (psi as? KtNamedFunction)?.hasModifier(KtTokens.TAILREC_KEYWORD) == true }, - ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - ExtraModifiers.KotlinOnlyModifiers.Override.takeIf { isOverride } - ).toSet().takeUnless { it.isEmpty() } - - private fun KtNamedClassOrObjectSymbol.additionalExtras() = listOfNotNull( - ExtraModifiers.KotlinOnlyModifiers.Inline.takeIf { (this.psi as? KtClass)?.isInline() == true }, - ExtraModifiers.KotlinOnlyModifiers.Value.takeIf { (this.psi as? KtClass)?.isValue() == true }, - ExtraModifiers.KotlinOnlyModifiers.External.takeIf { isExternal }, - ExtraModifiers.KotlinOnlyModifiers.Inner.takeIf { isInner }, - ExtraModifiers.KotlinOnlyModifiers.Data.takeIf { isData }, - ExtraModifiers.KotlinOnlyModifiers.Fun.takeIf { isFun }, - ).toSet().takeUnless { it.isEmpty() } - - private fun Modality.toDokkaModifier() = when (this) { - Modality.FINAL -> KotlinModifier.Final - Modality.SEALED -> KotlinModifier.Sealed - Modality.OPEN -> KotlinModifier.Open - Modality.ABSTRACT -> KotlinModifier.Abstract - } - - - private fun org.jetbrains.kotlin.descriptors.Visibility.toDokkaVisibility(): Visibility = when (this) { - Visibilities.Public -> KotlinVisibility.Public - Visibilities.Protected -> KotlinVisibility.Protected - Visibilities.Internal -> KotlinVisibility.Internal - Visibilities.Private, Visibilities.PrivateToThis -> KotlinVisibility.Private - JavaVisibilities.ProtectedAndPackage -> KotlinVisibility.Protected - JavaVisibilities.ProtectedStaticVisibility -> KotlinVisibility.Protected - JavaVisibilities.PackageVisibility -> JavaVisibility.Default - else -> KotlinVisibility.Public - } -} - - - - - - diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TranslatorError.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TranslatorError.kt deleted file mode 100644 index eceb7a38..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TranslatorError.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol -import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol - -internal class TranslatorError(message: String, cause: Throwable?) : IllegalStateException(message, cause) - -internal inline fun <R> KtAnalysisSession.withExceptionCatcher(symbol: KtSymbol, action: KtAnalysisSession.() -> R): R = - try { - action() - } catch (e: TranslatorError) { - throw e - } catch (e: Throwable) { - val file = try { - symbol.psi?.containingFile?.virtualFile?.path - } catch (e: Throwable) { - "[$e]" - } - val textRange = try { - symbol.psi?.textRange.toString() - } catch (e: Throwable) { - "[$e]" - } - throw TranslatorError( - "Error in translating of symbol (${(symbol as? KtNamedSymbol)?.name}) $symbol in file: $file, $textRange", - e - ) - } diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeReferenceFactory.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeReferenceFactory.kt deleted file mode 100644 index ea9a18c9..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeReferenceFactory.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - -import org.jetbrains.dokka.links.* -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection -import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance -import org.jetbrains.kotlin.analysis.api.KtTypeProjection -import org.jetbrains.kotlin.analysis.api.types.* - -internal fun KtAnalysisSession.getTypeReferenceFrom(type: KtType): TypeReference = - getTypeReferenceFromPossiblyRecursive(type, emptyList()) - - -// see `deep recursive typebound #1342` test -private fun KtAnalysisSession.getTypeReferenceFromPossiblyRecursive( - type: KtType, - paramTrace: List<KtType> -): TypeReference { - if (type is KtTypeParameterType) { - // compare by symbol since, e.g. T? and T have the different KtType, but the same type parameter - paramTrace.indexOfFirst { it is KtTypeParameterType && type.symbol == it.symbol } - .takeIf { it >= 0 } - ?.let { return RecursiveType(it) } - } - - return when (type) { - is KtNonErrorClassType -> TypeConstructor( - type.classId.asFqNameString(), - type.ownTypeArguments.map { - getTypeReferenceFromTypeProjection( - it, - paramTrace - ) - } - ) - - is KtTypeParameterType -> { - val upperBoundsOrNullableAny = - type.symbol.upperBounds.takeIf { it.isNotEmpty() } ?: listOf(this.builtinTypes.NULLABLE_ANY) - - TypeParam(bounds = upperBoundsOrNullableAny.map { - getTypeReferenceFromPossiblyRecursive( - it, - paramTrace + type - ) - }) - } - - is KtClassErrorType -> TypeConstructor("$ERROR_CLASS_NAME $type", emptyList()) - is KtFlexibleType -> getTypeReferenceFromPossiblyRecursive( - type.upperBound, - paramTrace - ) - - is KtDefinitelyNotNullType -> getTypeReferenceFromPossiblyRecursive( - type.original, - paramTrace - ) - - is KtDynamicType -> TypeConstructor("[dynamic]", emptyList()) - is KtTypeErrorType -> TypeConstructor("$ERROR_CLASS_NAME $type", emptyList()) - is KtCapturedType -> throw NotImplementedError() - is KtIntegerLiteralType -> throw NotImplementedError() - is KtIntersectionType -> throw NotImplementedError() - }.let { - if (type.isMarkedNullable) Nullable(it) else it - } - -} - -private fun KtAnalysisSession.getTypeReferenceFromTypeProjection( - typeProjection: KtTypeProjection, - paramTrace: List<KtType> -): TypeReference = - when (typeProjection) { - is KtStarTypeProjection -> StarProjection - is KtTypeArgumentWithVariance -> getTypeReferenceFromPossiblyRecursive(typeProjection.type, paramTrace) - } diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeTranslator.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeTranslator.kt deleted file mode 100644 index f7366294..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeTranslator.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.translators - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.kotlin.symbols.translators.AnnotationTranslator.Companion.getPresentableName -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection -import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance -import org.jetbrains.kotlin.analysis.api.KtTypeProjection -import org.jetbrains.kotlin.analysis.api.annotations.* -import org.jetbrains.kotlin.analysis.api.symbols.* -import org.jetbrains.kotlin.analysis.api.types.* - -internal const val ERROR_CLASS_NAME = "<ERROR CLASS>" - -/** - * Maps [KtType] to Dokka [Bound] or [TypeConstructorWithKind]. - * - * Also, build [AncestryNode] tree from [KtType] - */ -internal class TypeTranslator( - private val sourceSet: DokkaConfiguration.DokkaSourceSet, - private val annotationTranslator: AnnotationTranslator -) { - - private fun <T> T.toSourceSetDependent() = if (this != null) mapOf(sourceSet to this) else emptyMap() - - private fun KtAnalysisSession.toProjection(typeProjection: KtTypeProjection): Projection = - when (typeProjection) { - is KtStarTypeProjection -> Star - is KtTypeArgumentWithVariance -> toBoundFrom(typeProjection.type).wrapWithVariance(typeProjection.variance) - } - - private fun KtAnalysisSession.toTypeConstructorFromTypeAliased(classType: KtUsualClassType): TypeAliased { - val classSymbol = classType.classSymbol - return if (classSymbol is KtTypeAliasSymbol) - TypeAliased( - typeAlias = GenericTypeConstructor( - dri = getDRIFromNonErrorClassType(classType), - projections = classType.ownTypeArguments.map { toProjection(it) }), - inner = toBoundFrom(classType.fullyExpandedType), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(classType)?.toSourceSetDependent()?.toAnnotations() - ) - ) else - throw IllegalStateException("Expected type alias symbol in type") - } - - private fun KtAnalysisSession.toTypeConstructorFrom(classType: KtNonErrorClassType) = - GenericTypeConstructor( - dri = getDRIFromNonErrorClassType(classType), - projections = classType.ownTypeArguments.map { toProjection(it) }, - presentableName = classType.getPresentableName(), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(classType)?.toSourceSetDependent()?.toAnnotations() - ) - ) - - private fun KtAnalysisSession.toFunctionalTypeConstructorFrom(functionalType: KtFunctionalType) = - FunctionalTypeConstructor( - dri = getDRIFromNonErrorClassType(functionalType), - projections = functionalType.ownTypeArguments.map { toProjection(it) }, - isExtensionFunction = functionalType.receiverType != null, - isSuspendable = functionalType.isSuspend, - presentableName = functionalType.getPresentableName(), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(functionalType)?.toSourceSetDependent()?.toAnnotations() - ) - ) - - fun KtAnalysisSession.toBoundFrom(type: KtType): Bound = - when (type) { - is KtUsualClassType -> { - if (type.classSymbol is KtTypeAliasSymbol) toTypeConstructorFromTypeAliased(type) - else toTypeConstructorFrom(type) - } - - is KtTypeParameterType -> TypeParameter( - dri = getDRIFromTypeParameter(type.symbol), - name = type.name.asString(), - presentableName = type.getPresentableName(), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(type)?.toSourceSetDependent()?.toAnnotations() - ) - ) - - is KtClassErrorType -> UnresolvedBound(type.toString()) - is KtFunctionalType -> { - /** - * For example - * `typealias CompletionHandler = (cause: Throwable?) -> Unit` - * has functional type with no type arguments in K2 - * In K1 we have a usual generic type - */ - if (type.ownTypeArguments.isEmpty()) - toTypeConstructorFrom(type) - else - toFunctionalTypeConstructorFrom(type) - } - is KtDynamicType -> Dynamic - is KtDefinitelyNotNullType -> DefinitelyNonNullable( - toBoundFrom(type.original) - ) - - is KtFlexibleType -> TypeAliased( - toBoundFrom(type.upperBound), - toBoundFrom(type.lowerBound), - extra = PropertyContainer.withAll( - getDokkaAnnotationsFrom(type)?.toSourceSetDependent()?.toAnnotations() - ) - ) - - is KtTypeErrorType -> UnresolvedBound(type.toString()) - is KtCapturedType -> throw NotImplementedError() - is KtIntegerLiteralType -> throw NotImplementedError() - is KtIntersectionType -> throw NotImplementedError() - }.let { - if (type.isMarkedNullable) Nullable(it) else it - } - - fun KtAnalysisSession.buildAncestryInformationFrom( - type: KtType - ): AncestryNode { - val (interfaces, superclass) = type.getDirectSuperTypes().filterNot { it.isAny } - .partition { - val typeConstructorWithKind = toTypeConstructorWithKindFrom(it) - typeConstructorWithKind.kind == KotlinClassKindTypes.INTERFACE || - typeConstructorWithKind.kind == JavaClassKindTypes.INTERFACE - } - - return AncestryNode( - typeConstructor = toTypeConstructorWithKindFrom(type).typeConstructor, - superclass = superclass.map { buildAncestryInformationFrom(it) }.singleOrNull(), - interfaces = interfaces.map { buildAncestryInformationFrom(it) } - ) - } - - internal fun KtAnalysisSession.toTypeConstructorWithKindFrom(type: KtType): TypeConstructorWithKind = when (type) { - is KtUsualClassType -> - when (val classSymbol = type.classSymbol) { - is KtNamedClassOrObjectSymbol -> TypeConstructorWithKind( - toTypeConstructorFrom(type), - classSymbol.classKind.toDokkaClassKind() - ) - - is KtAnonymousObjectSymbol -> throw NotImplementedError() - is KtTypeAliasSymbol -> toTypeConstructorWithKindFrom(classSymbol.expandedType) - } - - is KtClassErrorType -> TypeConstructorWithKind( - GenericTypeConstructor( - dri = DRI(packageName = "", classNames = "$ERROR_CLASS_NAME $type"), - projections = emptyList(), - - ), - KotlinClassKindTypes.CLASS - ) - - is KtTypeErrorType -> TypeConstructorWithKind( - GenericTypeConstructor( - dri = DRI(packageName = "", classNames = "$ERROR_CLASS_NAME $type"), - projections = emptyList(), - - ), - KotlinClassKindTypes.CLASS - ) - - is KtFunctionalType -> TypeConstructorWithKind( - toFunctionalTypeConstructorFrom(type), - KotlinClassKindTypes.CLASS - ) - - is KtDefinitelyNotNullType -> toTypeConstructorWithKindFrom(type.original) - - is KtCapturedType -> throw NotImplementedError() - is KtDynamicType -> throw NotImplementedError() - is KtFlexibleType -> throw NotImplementedError() - is KtIntegerLiteralType -> throw NotImplementedError() - is KtIntersectionType -> throw NotImplementedError() - is KtTypeParameterType -> throw NotImplementedError() - } - - private fun KtAnalysisSession.getDokkaAnnotationsFrom(annotated: KtAnnotated): List<Annotations.Annotation>? = - with(annotationTranslator) { getAllAnnotationsFrom(annotated) }.takeUnless { it.isEmpty() } - - private fun KtClassKind.toDokkaClassKind() = when (this) { - KtClassKind.CLASS -> KotlinClassKindTypes.CLASS - KtClassKind.ENUM_CLASS -> KotlinClassKindTypes.ENUM_CLASS - KtClassKind.ANNOTATION_CLASS -> KotlinClassKindTypes.ANNOTATION_CLASS - KtClassKind.OBJECT -> KotlinClassKindTypes.OBJECT - KtClassKind.COMPANION_OBJECT -> KotlinClassKindTypes.OBJECT - KtClassKind.INTERFACE -> KotlinClassKindTypes.INTERFACE - KtClassKind.ANONYMOUS_OBJECT -> KotlinClassKindTypes.OBJECT - } -} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/utils/isException.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/utils/isException.kt deleted file mode 100644 index 08a2aaad..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/utils/isException.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.kotlin.symbols.utils - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.AncestryNode -import org.jetbrains.dokka.model.TypeConstructor - -internal fun AncestryNode.typeConstructorsBeingExceptions(): List<TypeConstructor> { - fun traverseSupertypes(ancestry: AncestryNode): List<TypeConstructor> = - listOf(ancestry.typeConstructor) + (ancestry.superclass?.let(::traverseSupertypes) ?: emptyList()) - - return traverseSupertypes(this).filter { type -> type.dri.isDirectlyAnException() } -} - -internal fun DRI.isDirectlyAnException(): Boolean = - toString().let { stringed -> - stringed == "kotlin/Exception///PointingToDeclaration/" || - stringed == "java.lang/Exception///PointingToDeclaration/" - } diff --git a/subprojects/analysis-kotlin-symbols/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/subprojects/analysis-kotlin-symbols/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin deleted file mode 100644 index e5f2922d..00000000 --- a/subprojects/analysis-kotlin-symbols/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. -# - -org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin diff --git a/subprojects/analysis-markdown-jb/README.md b/subprojects/analysis-markdown-jb/README.md deleted file mode 100644 index 2922abc8..00000000 --- a/subprojects/analysis-markdown-jb/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Ananlysis: Markdown (JetBrains) - -An internal module that encapsulates Markdown file and format parsing by using `org.jetbrains:markdown` -as the primary implementation dependency. - -Used by other Dokka modules, but it must not be used by external users directly until stable public API -is provided. diff --git a/subprojects/analysis-markdown-jb/api/analysis-markdown-jb.api b/subprojects/analysis-markdown-jb/api/analysis-markdown-jb.api deleted file mode 100644 index 3a8c37c5..00000000 --- a/subprojects/analysis-markdown-jb/api/analysis-markdown-jb.api +++ /dev/null @@ -1,28 +0,0 @@ -public final class org/jetbrains/dokka/analysis/markdown/jb/MarkdownApiKt { - public static final fun getMARKDOWN_ELEMENT_FILE_NAME ()Ljava/lang/String; -} - -public class org/jetbrains/dokka/analysis/markdown/jb/MarkdownParser : org/jetbrains/dokka/analysis/markdown/jb/Parser { - public static final field Companion Lorg/jetbrains/dokka/analysis/markdown/jb/MarkdownParser$Companion; - public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;)V - public fun parseStringToDocNode (Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/DocTag; - protected fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper; - protected fun preparse (Ljava/lang/String;)Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/markdown/jb/MarkdownParser$Companion { - public final fun fqDeclarationName (Lorg/jetbrains/dokka/links/DRI;)Ljava/lang/String; -} - -public final class org/jetbrains/dokka/analysis/markdown/jb/ParseUtilsKt { - public static final fun parseHtmlEncodedWithNormalisedSpaces (Ljava/lang/String;Z)Ljava/util/List; -} - -public abstract class org/jetbrains/dokka/analysis/markdown/jb/Parser { - public fun <init> ()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; - protected fun parseTagWithBody (Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/dokka/model/doc/TagWrapper; - protected abstract fun preparse (Ljava/lang/String;)Ljava/lang/String; -} - diff --git a/subprojects/analysis-markdown-jb/build.gradle.kts b/subprojects/analysis-markdown-jb/build.gradle.kts deleted file mode 100644 index 96b72a85..00000000 --- a/subprojects/analysis-markdown-jb/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -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("analysisMarkdown") { - artifactId = "analysis-markdown" -} diff --git a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownApi.kt b/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownApi.kt deleted file mode 100644 index bc56b596..00000000 --- a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownApi.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.markdown.jb - -import org.intellij.markdown.MarkdownElementTypes -import org.jetbrains.dokka.InternalDokkaApi - -// TODO [beresnev] move/rename if it's only used for CustomDocTag. for now left as is for compatibility -@InternalDokkaApi -public val MARKDOWN_ELEMENT_FILE_NAME: String = MarkdownElementTypes.MARKDOWN_FILE.name diff --git a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownParser.kt b/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownParser.kt deleted file mode 100644 index 130c6def..00000000 --- a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/MarkdownParser.kt +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.markdown.jb - -import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.MarkdownTokenTypes -import org.intellij.markdown.ast.ASTNode -import org.intellij.markdown.ast.CompositeASTNode -import org.intellij.markdown.ast.LeafASTNode -import org.intellij.markdown.ast.impl.ListItemCompositeNode -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.InternalDokkaApi -import org.jetbrains.dokka.analysis.markdown.jb.factories.DocTagsFromIElementFactory -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.PointingToDeclaration -import org.jetbrains.dokka.model.doc.* -import java.net.MalformedURLException -import java.net.URL -import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser - -@InternalDokkaApi -public open class MarkdownParser( - private val externalDri: (String) -> DRI?, - private val kdocLocation: String?, -) : Parser() { - - private lateinit var destinationLinksMap: Map<String, String> - private lateinit var text: String - - override fun parseStringToDocNode(extractedString: String): DocTag { - val gfmFlavourDescriptor = GFMFlavourDescriptor() - val markdownAstRoot = IntellijMarkdownParser(gfmFlavourDescriptor).buildMarkdownTreeFromString(extractedString) - destinationLinksMap = getAllDestinationLinks(extractedString, markdownAstRoot).toMap() - text = extractedString - - val parsed = visitNode(markdownAstRoot) - if (parsed.size == 1) { - return parsed.first() - } - return CustomDocTag(children = parsed, params = emptyMap(), name = "") - } - - override fun preparse(text: String): String = text.replace("\r\n", "\n").replace("\r", "\n") - - override fun parseTagWithBody(tagName: String, content: String): TagWrapper = - when (tagName) { - "see" -> { - val referencedName = content.substringBefore(' ') - val dri = externalDri(referencedName) - See( - parseStringToDocNode(content.substringAfter(' ')), - dri?.fqDeclarationName() ?: referencedName, - dri - ) - } - "throws", "exception" -> { - val dri = externalDri(content.substringBefore(' ')) - Throws( - parseStringToDocNode(content.substringAfter(' ')), - dri?.fqDeclarationName() ?: content.substringBefore(' '), - dri - ) - } - else -> super.parseTagWithBody(tagName, content) - } - - private fun headersHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } - ?: throw detailedException("Wrong AST Tree. Header does not contain expected content", node) - ).flatMap { it.children } - ) - - /** - * Handler for [MarkdownTokenTypes.ATX_CONTENT], which is the content of the header - * elements like [MarkdownElementTypes.ATX_1], [MarkdownElementTypes.ATX_2] and so on. - * - * For example, a header line like `# Header text` is expected to be parsed into: - * - One [MarkdownTokenTypes.ATX_HEADER] with startOffset = 0, endOffset = 1 (only the `#` symbol) - * - Composite [MarkdownTokenTypes.ATX_CONTENT] with four children: WHITE_SPACE, TEXT, WHITE_SPACE, TEXT. - */ - private fun headerContentHandler(node: ASTNode): List<DocTag> { - // ATX_CONTENT contains everything after the `#` symbol, so if there's a space - // in-between the `#` symbol and the text (like `# header`), it will be present here too. - // However, we don't need the leading space between the `#` symbol and the text, nor do we need trailing spaces, - // so we just skip it (otherwise the header text will be parsed as `<whitespace>header` instead of `header`). - // If there's more space between `#` and text, like `# header`, it will still be a single WHITE_SPACE - // element, but it will be wider, so the solution below should still hold. The same applies to trailing spaces. - val trimmedChildren = node.children.trimWhitespaceToken() - - val children = trimmedChildren.evaluateChildren() - return DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.PARAGRAPH, // PARAGRAPH instead of TEXT to preserve compatibility with prev. versions - children = children - ) - } - - /** - * @return a sublist of [this] list that does not contain - * leading and trailing [MarkdownTokenTypes.WHITE_SPACE] elements - */ - private fun List<ASTNode>.trimWhitespaceToken(): List<ASTNode> { - val firstNonWhitespaceIndex = this.indexOfFirst { it.type != MarkdownTokenTypes.WHITE_SPACE } - if (firstNonWhitespaceIndex == -1) { - return this - } - val lastNonWhitespaceIndex = this.indexOfLast { it.type != MarkdownTokenTypes.WHITE_SPACE } - - return this.subList(firstNonWhitespaceIndex, lastNonWhitespaceIndex + 1) - } - - private fun horizontalRulesHandler() = - DocTagsFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE) - - private fun emphasisHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(1) - ) - - private fun strongHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2) - ) - - private fun List<ASTNode>.evaluateChildrenWithDroppedEnclosingTokens(count: Int) = - drop(count).dropLast(count).evaluateChildren() - - private fun blockquotesHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, children = node.children - .filterIsInstance<CompositeASTNode>() - .evaluateChildren() - ) - - private fun listsHandler(node: ASTNode): List<DocTag> { - - val children = node.children.filterIsInstance<ListItemCompositeNode>().flatMap { - if (it.children.last().type in listOf( - MarkdownElementTypes.ORDERED_LIST, - MarkdownElementTypes.UNORDERED_LIST - ) - ) { - val nestedList = it.children.last() - (it.children as MutableList).removeAt(it.children.lastIndex) - listOf(it, nestedList) - } else - listOf(it) - } - - return DocTagsFromIElementFactory.getInstance( - node.type, - children = - children - .flatMap { - if (it.type == MarkdownElementTypes.LIST_ITEM) - DocTagsFromIElementFactory.getInstance( - it.type, - children = it - .children - .filterIsInstance<CompositeASTNode>() - .evaluateChildren() - ) - else - visitNode(it) - }, - params = - if (node.type == MarkdownElementTypes.ORDERED_LIST) { - val listNumberNode = node.children.first().children.first() - mapOf( - "start" to text.substring( - listNumberNode.startOffset, - listNumberNode.endOffset - ).trim().dropLast(1) - ) - } else - emptyMap() - ) - } - - private fun resolveDRI(mdLink: String): DRI? = - mdLink - .removePrefix("[") - .removeSuffix("]") - .let { link -> - try { - URL(link) - null - } catch (e: MalformedURLException) { - externalDri(link) - } - } - - private fun getAllDestinationLinks(text: String, node: ASTNode): List<Pair<String, String>> = - node.children - .filter { it.type == MarkdownElementTypes.LINK_DEFINITION } - .map { - text.substring(it.children[0].startOffset, it.children[0].endOffset).toLowerCase() to - text.substring(it.children[2].startOffset, it.children[2].endOffset) - } + - node.children.filterIsInstance<CompositeASTNode>().flatMap { getAllDestinationLinks(text, it) } - - - private fun referenceLinksHandler(node: ASTNode): List<DocTag> { - val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL } - ?: throw detailedException("Wrong AST Tree. Reference link does not contain link label", node) - val linkText = node.children.findLast { it.type == MarkdownElementTypes.LINK_TEXT } ?: linkLabel - - val linkKey = text.substring(linkLabel.startOffset, linkLabel.endOffset) - - val link = destinationLinksMap[linkKey.toLowerCase()] ?: linkKey - - return linksHandler(linkText, link) - } - - private fun inlineLinksHandler(node: ASTNode): List<DocTag> { - val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT } - ?: throw detailedException("Wrong AST Tree. Inline link does not contain link text", node) - val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION } - val linkTitle = node.children.find { it.type == MarkdownElementTypes.LINK_TITLE } - - // Link destination may be ommited: https://github.github.com/gfm/#example-495 - val link = linkDestination?.let { text.substring(it.startOffset, it.endOffset) } - - return linksHandler(linkText, link, linkTitle) - } - - private fun markdownFileHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children - .filterSpacesAndEOL() - .evaluateChildren() - ) - - private fun autoLinksHandler(node: ASTNode): List<DocTag> { - val link = text.substring(node.startOffset + 1, node.endOffset - 1) - - return linksHandler(node, link) - } - - private fun linksHandler(linkText: ASTNode, link: String?, linkTitle: ASTNode? = null): List<DocTag> { - val dri: DRI? = link?.let { resolveDRI(it) } - val linkOrEmpty = link ?: "" - val linkTextString = - if (linkTitle == null) linkOrEmpty else text.substring(linkTitle.startOffset + 1, linkTitle.endOffset - 1) - - val params = if (linkTitle == null) - mapOf("href" to linkOrEmpty) - else - mapOf("href" to linkOrEmpty, "title" to linkTextString) - - return if (link != null && dri == null && !linkOrEmpty.isRemoteLink()) { - DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - params = params, - children = linkText.children.drop(1).dropLast(1).evaluateChildren(), - body = linkTextString.removeSurrounding("[", "]") - ) - } else { - DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.INLINE_LINK, - params = params, - children = linkText.children.drop(1).dropLast(1).evaluateChildren(), - dri = dri - ) - } - } - - private fun codeLineHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.CODE_BLOCK, - body = text.substring(node.startOffset, node.endOffset) - ) - - private fun textHandler(node: ASTNode, keepAllFormatting: Boolean) = DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset, node.endOffset).transform(), - keepFormatting = keepAllFormatting - ) - - private fun strikeThroughHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2) - ) - - private fun tableHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.TABLE, - children = node.children - .filter { it.type == GFMElementTypes.ROW || it.type == GFMElementTypes.HEADER } - .evaluateChildren() - ) - - private fun headerHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.HEADER, - children = node.children - .filter { it.type == GFMTokenTypes.CELL } - .evaluateChildren() - ) - - private fun rowHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.ROW, - children = node.children - .filter { it.type == GFMTokenTypes.CELL } - .evaluateChildren() - ) - - private fun cellHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMTokenTypes.CELL, - children = node.children.filterTabSeparators().evaluateChildren().trimSurroundingTokensIfText() - ) - - private fun String.isRemoteLink() = try { - URL(this) - true - } catch (e: MalformedURLException) { - false - } - - private fun imagesHandler(node: ASTNode): List<DocTag> = - with(node.children.last().children) { - val destination = find { it.type == MarkdownElementTypes.LINK_DESTINATION } - val description = find { it.type == MarkdownElementTypes.LINK_TEXT } - - val src = destination?.let { - mapOf("href" to text.substring(it.startOffset, it.endOffset)) - } ?: emptyMap() - - val alt = description?.let { - mapOf("alt" to text.substring(it.startOffset + 1, it.endOffset - 1)) - } ?: emptyMap() - - return DocTagsFromIElementFactory.getInstance( - node.type, - params = src + alt - ) - } - - - private fun rawHtmlHandler(node: ASTNode): List<DocTag> = - DocTagsFromIElementFactory.getInstance( - node.type, - body = text.substring(node.startOffset, node.endOffset) - ) - - private fun codeSpansHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent(), - keepFormatting = true - ) - ) - - private fun codeFencesHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node - .children - .dropWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } - .dropLastWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } - .filter { it.type != MarkdownTokenTypes.WHITE_SPACE } - .map { - if (it.type == MarkdownTokenTypes.EOL) - LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0) - else - it - }.evaluateChildren(keepAllFormatting = true), - params = node - .children - .find { it.type == MarkdownTokenTypes.FENCE_LANG } - ?.let { mapOf("lang" to text.substring(it.startOffset, it.endOffset)) } - ?: emptyMap() - ) - - private fun codeBlocksHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance(node.type, children = node.children.mergeLeafASTNodes().flatMap { - DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = HtmlGenerator.trimIndents(text.substring(it.startOffset, it.endOffset), 4).toString() - ) - }) - - private fun defaultHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.PARAGRAPH, - children = node.children.evaluateChildren() - ) - - private fun visitNode(node: ASTNode, keepAllFormatting: Boolean = false): List<DocTag> = - when (node.type) { - MarkdownElementTypes.ATX_1, - MarkdownElementTypes.ATX_2, - MarkdownElementTypes.ATX_3, - MarkdownElementTypes.ATX_4, - MarkdownElementTypes.ATX_5, - MarkdownElementTypes.ATX_6, - -> headersHandler(node) - MarkdownTokenTypes.ATX_CONTENT -> headerContentHandler(node) - MarkdownTokenTypes.HORIZONTAL_RULE -> horizontalRulesHandler() - MarkdownElementTypes.STRONG -> strongHandler(node) - MarkdownElementTypes.EMPH -> emphasisHandler(node) - MarkdownElementTypes.FULL_REFERENCE_LINK, - MarkdownElementTypes.SHORT_REFERENCE_LINK, - -> referenceLinksHandler(node) - MarkdownElementTypes.INLINE_LINK -> inlineLinksHandler(node) - MarkdownElementTypes.AUTOLINK -> autoLinksHandler(node) - MarkdownElementTypes.BLOCK_QUOTE -> blockquotesHandler(node) - MarkdownElementTypes.UNORDERED_LIST, - MarkdownElementTypes.ORDERED_LIST, - -> listsHandler(node) - MarkdownElementTypes.CODE_BLOCK -> codeBlocksHandler(node) - MarkdownElementTypes.CODE_FENCE -> codeFencesHandler(node) - MarkdownElementTypes.CODE_SPAN -> codeSpansHandler(node) - MarkdownElementTypes.IMAGE -> imagesHandler(node) - MarkdownElementTypes.HTML_BLOCK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT, - -> rawHtmlHandler(node) - MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type) - MarkdownTokenTypes.CODE_FENCE_CONTENT, - MarkdownTokenTypes.CODE_LINE, - -> codeLineHandler(node) - MarkdownTokenTypes.TEXT -> textHandler(node, keepAllFormatting) - MarkdownElementTypes.MARKDOWN_FILE -> markdownFileHandler(node) - GFMElementTypes.STRIKETHROUGH -> strikeThroughHandler(node) - GFMElementTypes.TABLE -> tableHandler(node) - GFMElementTypes.HEADER -> headerHandler(node) - GFMElementTypes.ROW -> rowHandler(node) - GFMTokenTypes.CELL -> cellHandler(node) - else -> defaultHandler(node) - } - - private fun List<ASTNode>.filterTabSeparators() = - this.filterNot { it.type == GFMTokenTypes.TABLE_SEPARATOR } - - private fun List<ASTNode>.filterSpacesAndEOL() = - this.filterNot { it.type == MarkdownTokenTypes.WHITE_SPACE || it.type == MarkdownTokenTypes.EOL } - - private fun List<ASTNode>.evaluateChildren(keepAllFormatting: Boolean = false): List<DocTag> = - this.removeUselessTokens().swapImagesThatShouldBeLinks(keepAllFormatting).mergeLeafASTNodes().flatMap { visitNode(it, keepAllFormatting) } - - private fun List<ASTNode>.swapImagesThatShouldBeLinks(keepAllFormatting: Boolean): List<ASTNode> = - if (keepAllFormatting) { - this - } else { - flatMap { node -> - if (node.type == MarkdownElementTypes.IMAGE - && node.children.firstOrNull()?.let { it is LeafASTNode && it.type.name == "!" } == true - && node.children.lastOrNull()?.type == MarkdownElementTypes.SHORT_REFERENCE_LINK - ) { - node.children - } else { - listOf(node) - } - } - } - - private fun List<ASTNode>.removeUselessTokens(): List<ASTNode> = - this.filterIndexed { index, node -> - !(node.type == MarkdownElementTypes.LINK_DEFINITION || ( - node.type == MarkdownTokenTypes.EOL && - this.getOrNull(index - 1)?.type == MarkdownTokenTypes.HARD_LINE_BREAK - )) - } - - private fun List<DocTag>.trimSurroundingTokensIfText() = mapIndexed { index, elem -> - val elemTransformed = if (index == 0 && elem is Text) elem.copy(elem.body.trimStart()) else elem - if (index == lastIndex && elemTransformed is Text) elemTransformed.copy(elemTransformed.body.trimEnd()) else elemTransformed - } - - private val notLeafNodes = listOf( - MarkdownTokenTypes.HORIZONTAL_RULE, - MarkdownTokenTypes.HARD_LINE_BREAK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT - ) - - private fun ASTNode.isNotLeaf() = this is CompositeASTNode || this.type in notLeafNodes - - private fun List<ASTNode>.isNotLeaf(index: Int): Boolean = - if (index in 0..this.lastIndex) - this[index].isNotLeaf() - else - false - - private fun List<ASTNode>.mergeLeafASTNodes(): List<ASTNode> { - val children: MutableList<ASTNode> = mutableListOf() - var index = 0 - while (index <= this.lastIndex) { - if (this.isNotLeaf(index)) { - children += this[index] - } else { - val startOffset = this[index].startOffset - val sIndex = index - while (index < this.lastIndex) { - if (this.isNotLeaf(index + 1) || this[index + 1].startOffset != this[index].endOffset) { - children += mergedLeafNode(this, index, startOffset, sIndex) - break - } - index++ - } - if (index == this.lastIndex) { - children += mergedLeafNode(this, index, startOffset, sIndex) - } - } - index++ - } - return children - } - - private fun mergedLeafNode(nodes: List<ASTNode>, index: Int, startOffset: Int, sIndex: Int): LeafASTNode { - val endOffset = nodes[index].endOffset - val type = if (nodes.subList(sIndex, index) - .any { it.type == MarkdownTokenTypes.CODE_LINE } - ) MarkdownTokenTypes.CODE_LINE else MarkdownTokenTypes.TEXT - return LeafASTNode(type, startOffset, endOffset) - } - - private fun String.transform() = this - .replace(Regex("\n\n+"), "") // Squashing new lines between paragraphs - .replace(Regex("\n"), " ") - .replace(Regex(" >+ +"), " ") // Replacement used in blockquotes, get rid of garbage - - private fun detailedException(baseMessage: String, node: ASTNode) = - IllegalStateException( - baseMessage + " in ${kdocLocation ?: "unspecified location"}, element starts from offset ${node.startOffset} and ends ${node.endOffset}: ${ - text.substring( - node.startOffset, - node.endOffset - ) - }" - ) - - - public companion object { - public fun DRI.fqDeclarationName(): String? { - if (this.target !is PointingToDeclaration) { - return null - } - return listOfNotNull(this.packageName, this.classNames, this.callable?.name) - .joinToString(separator = ".") - .takeIf { it.isNotBlank() } - } - } -} - diff --git a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/ParseUtils.kt b/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/ParseUtils.kt deleted file mode 100644 index 0293d470..00000000 --- a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/ParseUtils.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.markdown.jb - -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 -public fun String.parseHtmlEncodedWithNormalisedSpaces( - renderWhiteCharactersAsSpaces: Boolean -): List<DocTag> { - val accum = StringBuilder() - val tags = mutableListOf<DocTag>() - 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/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/Parser.kt b/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/Parser.kt deleted file mode 100644 index 28afa0c4..00000000 --- a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/Parser.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.markdown.jb - -import org.jetbrains.dokka.InternalDokkaApi -import org.jetbrains.dokka.model.doc.* - -@InternalDokkaApi -public abstract class Parser { - - public abstract fun parseStringToDocNode(extractedString: String): DocTag - - protected abstract fun preparse(text: String): String - - public open fun parse(text: String): DocumentationNode = - DocumentationNode(extractTagsToListOfPairs(preparse(text)).map { (tag, content) -> parseTagWithBody(tag, content) }) - - protected open fun parseTagWithBody(tagName: String, content: String): TagWrapper = - when (tagName) { - "description" -> Description(parseStringToDocNode(content)) - "author" -> Author(parseStringToDocNode(content)) - "version" -> Version(parseStringToDocNode(content)) - "since" -> Since(parseStringToDocNode(content)) - "see" -> See( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' '), - null - ) - "param" -> Param( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "property" -> Property( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "return" -> Return(parseStringToDocNode(content)) - "constructor" -> Constructor(parseStringToDocNode(content)) - "receiver" -> Receiver(parseStringToDocNode(content)) - "throws", "exception" -> Throws( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' '), - null - ) - "deprecated" -> Deprecated(parseStringToDocNode(content)) - "sample" -> Sample( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "suppress" -> Suppress(parseStringToDocNode(content)) - else -> CustomTagWrapper(parseStringToDocNode(content), tagName) - } - - /** - * KDoc parser from Kotlin compiler relies on a comment asterisk - * So there is a mini parser here - * TODO: at least to adapt [org.jetbrains.kotlin.kdoc.lexer.KDocLexer] to analyze KDoc without the asterisks and use it here - */ - private fun extractTagsToListOfPairs(text: String): List<Pair<String, String>> = - "description $text" - .extractKDocSections() - .map { content -> - val contentWithEscapedAts = content.replace("\\@", "@") - val (tag, body) = contentWithEscapedAts.split(" ", limit = 2) - tag to body - } - - /** - * Ignore a doc tag inside code spans and blocks - * @see org.jetbrains.kotlin.kdoc.psi.impl.KDocSection - */ - private fun CharSequence.extractKDocSections(delimiter: String = "\n@"): List<String> { - var countOfBackticks = 0 - var countOfTildes = 0 - var countOfBackticksInOpeningFence = 0 - var countOfTildesInOpeningFence = 0 - - var isInCode = false - val result = mutableListOf<String>() - var rangeStart = 0 - var rangeEnd = 0 - var currentOffset = 0 - while (currentOffset < length) { - - when (get(currentOffset)) { - '`' -> { - countOfBackticks++ - countOfTildes = 0 - } - '~' -> { - countOfTildes++ - countOfBackticks = 0 - } - else -> { - if (isInCode) { - // The closing code fence must be at least as long as the opening fence - if(countOfBackticks >= countOfBackticksInOpeningFence - || countOfTildes >= countOfTildesInOpeningFence) - isInCode = false - } else { - // as per CommonMark spec, there can be any number of backticks for a code span, not only one or three - if (countOfBackticks > 0) { - isInCode = true - countOfBackticksInOpeningFence = countOfBackticks - countOfTildesInOpeningFence = Int.MAX_VALUE - } - // tildes are only for a code block, not code span - if (countOfTildes >= 3) { - isInCode = true - countOfTildesInOpeningFence = countOfTildes - countOfBackticksInOpeningFence = Int.MAX_VALUE - } - } - countOfTildes = 0 - countOfBackticks = 0 - } - } - if (!isInCode && startsWith(delimiter, currentOffset)) { - result.add(substring(rangeStart, rangeEnd)) - currentOffset += delimiter.length - rangeStart = currentOffset - rangeEnd = currentOffset - continue - } - - ++rangeEnd - ++currentOffset - } - result.add(substring(rangeStart, rangeEnd)) - return result - } - -} diff --git a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/factories/DocTagsFromIElementFactory.kt b/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/factories/DocTagsFromIElementFactory.kt deleted file mode 100644 index 77ca92d5..00000000 --- a/subprojects/analysis-markdown-jb/src/main/kotlin/org/jetbrains/dokka/analysis/markdown/jb/factories/DocTagsFromIElementFactory.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.analysis.markdown.jb.factories - -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.analysis.markdown.jb.MARKDOWN_ELEMENT_FILE_NAME -import org.jetbrains.dokka.analysis.markdown.jb.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 - -internal object DocTagsFromIElementFactory { - - @Suppress("IMPLICIT_CAST_TO_ANY") - fun getInstance(type: IElementType, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null, keepFormatting: Boolean = false) = - when(type) { - MarkdownElementTypes.SHORT_REFERENCE_LINK, - MarkdownElementTypes.FULL_REFERENCE_LINK, - MarkdownElementTypes.INLINE_LINK -> if(dri == null) A(children, params) else DocumentationLink(dri, children, params) - MarkdownElementTypes.STRONG -> B(children, params) - MarkdownElementTypes.BLOCK_QUOTE -> BlockQuote(children, params) - MarkdownElementTypes.CODE_SPAN -> CodeInline(children, params) - MarkdownElementTypes.CODE_BLOCK, - MarkdownElementTypes.CODE_FENCE -> CodeBlock(children, params) - MarkdownElementTypes.ATX_1 -> H1(children, params) - MarkdownElementTypes.ATX_2 -> H2(children, params) - MarkdownElementTypes.ATX_3 -> H3(children, params) - MarkdownElementTypes.ATX_4 -> H4(children, params) - MarkdownElementTypes.ATX_5 -> H5(children, params) - MarkdownElementTypes.ATX_6 -> H6(children, params) - MarkdownElementTypes.EMPH -> I(children, params) - MarkdownElementTypes.IMAGE -> Img(children, params) - MarkdownElementTypes.LIST_ITEM -> Li(children, params) - MarkdownElementTypes.ORDERED_LIST -> Ol(children, params) - MarkdownElementTypes.UNORDERED_LIST -> Ul(children, params) - MarkdownElementTypes.PARAGRAPH -> P(children, params) - MarkdownTokenTypes.TEXT -> if (keepFormatting) Text( - body.orEmpty(), - children, - params - ) else { - // corner case: there are only spaces between two Markdown nodes - val containsOnlySpaces = body?.isNotEmpty() == true && body.all { it.isWhitespace() } - if (containsOnlySpaces) Text(" ", children, params) - else body?.parseWithNormalisedSpaces(renderWhiteCharactersAsSpaces = false).orEmpty() - } - MarkdownTokenTypes.HORIZONTAL_RULE -> HorizontalRule - MarkdownTokenTypes.HARD_LINE_BREAK -> Br - GFMElementTypes.STRIKETHROUGH -> Strikethrough(children, params) - GFMElementTypes.TABLE -> Table(children, params) - GFMElementTypes.HEADER -> Th(children, params) - GFMElementTypes.ROW -> Tr(children, params) - GFMTokenTypes.CELL -> Td(children, params) - MarkdownElementTypes.MARKDOWN_FILE -> CustomDocTag(children, params, MARKDOWN_ELEMENT_FILE_NAME) - MarkdownElementTypes.HTML_BLOCK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT -> Text(body.orEmpty(), params = params + contentTypeParam("html")) - else -> CustomDocTag(children, params, type.name) - }.let { - @Suppress("UNCHECKED_CAST") - when (it) { - is List<*> -> it as List<DocTag> - 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<DocTag> { - 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 -} |