From 8e5c63d035ef44a269b8c43430f43f5c8eebfb63 Mon Sep 17 00:00:00 2001 From: Ignat Beresnev Date: Fri, 10 Nov 2023 11:46:54 +0100 Subject: Restructure the project to utilize included builds (#3174) * Refactor and simplify artifact publishing * Update Gradle to 8.4 * Refactor and simplify convention plugins and build scripts Fixes #3132 --------- Co-authored-by: Adam <897017+aSemy@users.noreply.github.com> Co-authored-by: Oleg Yukhnevich --- .../java/DefaultPsiToDocumentableTranslator.kt | 87 --- .../dokka/analysis/java/JavaAnalysisPlugin.kt | 110 --- .../jetbrains/dokka/analysis/java/JavadocTag.kt | 54 -- .../java/SynheticElementDocumentationProvider.kt | 46 -- .../dokka/analysis/java/doccomment/DocComment.kt | 18 - .../analysis/java/doccomment/DocCommentCreator.kt | 13 - .../analysis/java/doccomment/DocCommentFactory.kt | 24 - .../analysis/java/doccomment/DocCommentFinder.kt | 68 -- .../java/doccomment/DocumentationContent.kt | 15 - .../analysis/java/doccomment/JavaDocComment.kt | 88 --- .../java/doccomment/JavaDocCommentCreator.kt | 15 - .../java/doccomment/PsiDocumentationContent.kt | 26 - .../java/parsers/CommentResolutionContext.kt | 13 - .../analysis/java/parsers/DocCommentParser.kt | 16 - .../dokka/analysis/java/parsers/DokkaPsiParser.kt | 803 --------------------- .../analysis/java/parsers/JavaDocCommentParser.kt | 232 ------ .../dokka/analysis/java/parsers/JavadocParser.kt | 28 - .../java/parsers/doctag/DocTagParserContext.kt | 51 -- .../java/parsers/doctag/HtmlToDocTagConverter.kt | 118 --- .../parsers/doctag/InheritDocTagContentProvider.kt | 14 - .../java/parsers/doctag/InheritDocTagResolver.kt | 118 --- .../java/parsers/doctag/PsiDocTagParser.kt | 43 -- .../parsers/doctag/PsiElementToHtmlConverter.kt | 218 ------ .../dokka/analysis/java/util/CoreCopyPaste.kt | 24 - .../dokka/analysis/java/util/NoopIntellijLogger.kt | 47 -- .../analysis/java/util/PropertiesConventionUtil.kt | 105 --- .../java/util/PsiAccessorConventionUtil.kt | 102 --- .../dokka/analysis/java/util/PsiCommentsUtils.kt | 53 -- .../jetbrains/dokka/analysis/java/util/PsiUtil.kt | 126 ---- .../dokka/analysis/java/util/StdlibUtil.kt | 37 - .../dokka/analysis/java/util/resolveToGetDri.kt | 11 - .../org.jetbrains.dokka.plugability.DokkaPlugin | 5 - 32 files changed, 2728 deletions(-) delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/DefaultPsiToDocumentableTranslator.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavaAnalysisPlugin.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/JavadocTag.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/SynheticElementDocumentationProvider.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocComment.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentCreator.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFactory.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocCommentFinder.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/DocumentationContent.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocComment.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/JavaDocCommentCreator.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/doccomment/PsiDocumentationContent.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/CommentResolutionContext.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DocCommentParser.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/DokkaPsiParser.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavaDocCommentParser.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/JavadocParser.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/DocTagParserContext.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/HtmlToDocTagConverter.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagContentProvider.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/InheritDocTagResolver.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiDocTagParser.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/parsers/doctag/PsiElementToHtmlConverter.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/CoreCopyPaste.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/NoopIntellijLogger.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PropertiesConventionUtil.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiAccessorConventionUtil.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiCommentsUtils.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/PsiUtil.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/StdlibUtil.kt delete mode 100644 subprojects/analysis-java-psi/src/main/kotlin/org/jetbrains/dokka/analysis/java/util/resolveToGetDri.kt delete mode 100644 subprojects/analysis-java-psi/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin (limited to 'subprojects/analysis-java-psi/src') 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().querySingle { projectProvider } - val project = projectProvider.getProject(sourceSet, context) - - val sourceRootsExtractor = context.plugin().querySingle { sourceRootsExtractor } - val sourceRoots = sourceRootsExtractor.extract(sourceSet, context) - - val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file") - - val psiFiles = sourceRoots.parallelMap { sourceRoot -> - sourceRoot.absoluteFile.walkTopDown().mapNotNull { - localFileSystem.findFileByPath(it.path)?.let { vFile -> - PsiManager.getInstance(project).findFile(vFile) as? PsiJavaFile - } - }.toList() - }.flatten() - - val docParser = createPsiParser(sourceSet, context) - - DModule( - name = context.configuration.moduleName, - packages = psiFiles.parallelMapNotNull { it }.groupBy { it.packageName }.toList() - .parallelMap { (packageName: String, psiFiles: List) -> - docParser.parsePackage(packageName, psiFiles) - }, - documentation = emptyMap(), - expectPresentInSet = null, - sourceSets = setOf(sourceSet) - ) - } - } - - private fun createPsiParser(sourceSet: DokkaSourceSet, context: DokkaContext): DokkaPsiParser { - val projectProvider = context.plugin().querySingle { projectProvider } - val docCommentParsers = context.plugin().query { docCommentParsers } - return DokkaPsiParser( - sourceSetData = sourceSet, - project = projectProvider.getProject(sourceSet, context), - logger = context.logger, - javadocParser = JavadocParser( - docCommentParsers = docCommentParsers, - docCommentFinder = context.plugin().docCommentFinder - ), - javaPsiDocCommentParser = docCommentParsers.single { it is JavaPsiDocCommentParser } as JavaPsiDocCommentParser, - lightMethodChecker = context.plugin().querySingle { kotlinLightMethodChecker } - ) - } -} - -internal fun PsiModifierListOwner.getVisibility() = modifierList?.let { - val ml = it.children.toList() - when { - ml.any { it.text == PsiKeyword.PUBLIC } || it.hasModifierProperty("public") -> JavaVisibility.Public - ml.any { it.text == PsiKeyword.PROTECTED } || it.hasModifierProperty("protected") -> JavaVisibility.Protected - ml.any { it.text == PsiKeyword.PRIVATE } || it.hasModifierProperty("private") -> JavaVisibility.Private - else -> JavaVisibility.Default - } -} ?: JavaVisibility.Default diff --git a/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 -} - -@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 by extensionPoint() - - // single - public val sourceRootsExtractor: ExtensionPoint by extensionPoint() - - // multiple - public val docCommentCreators: ExtensionPoint by extensionPoint() - - // multiple - public val docCommentParsers: ExtensionPoint by extensionPoint() - - // none or more - public val inheritDocTagContentProviders: ExtensionPoint by extensionPoint() - - // TODO [beresnev] figure out a better way depending on what it's used for - public val kotlinLightMethodChecker: ExtensionPoint 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 -} 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 -) { - 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() - .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 -} 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() - ?.resolveToElement() - ?.getKotlinFqName() == tag.exceptionQualifiedName - - override fun resolveTag(tag: JavadocTag): List { - return when (tag) { - is ParamJavadocTag -> resolveParamTag(tag) - is ThrowingExceptionJavadocTag -> resolveThrowingTag(tag) - else -> comment.resolveTag(tag).map { PsiDocumentationContent(it, tag) } - } - } - - private fun resolveParamTag(tag: ParamJavadocTag): List { - val resolvedParamElements = comment.resolveTag(tag) - .filterIsInstance() - .map { it.contentElementsWithSiblingIfNeeded() } - .firstOrNull { - it.firstOrNull()?.text == tag.method.parameterList.parameters[tag.paramIndex].name - }.orEmpty() - - return resolvedParamElements - .withoutReferenceLink() - .map { PsiDocumentationContent(it, tag) } - } - - private fun resolveThrowingTag(tag: ThrowingExceptionJavadocTag): List { - val resolvedElements = comment.resolveTag(tag) - .flatMap { - when (it) { - is PsiDocTag -> it.contentElementsWithSiblingIfNeeded() - else -> listOf(it) - } - } - - return resolvedElements - .withoutReferenceLink() - .map { PsiDocumentationContent(it, tag) } - } - - private fun PsiDocComment.resolveTag(tag: JavadocTag): List { - return when (tag) { - DescriptionJavadocTag -> this.descriptionElements.toList() - else -> this.findTagsByName(tag.name).toList() - } - } - - private fun List.withoutReferenceLink(): List = drop(1) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as JavaDocComment - - if (comment != other.comment) return false - - return true - } - - override fun hashCode(): Int { - return comment.hashCode() - } -} diff --git a/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 { - 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() - - private val PsiMethod.hash: Int - get() = "$returnType $name$parameterList".hashCode() - - private val PsiField.hash: Int - get() = "$type $name".hashCode() - - private val PsiClassType.shouldBeIgnored: Boolean - get() = isClass("java.lang.Enum") || isClass("java.lang.Object") - - private fun PsiClassType.isClass(qName: String): Boolean { - val shortName = qName.substringAfterLast('.') - if (className == shortName) { - val psiClass = resolve() - return psiClass?.qualifiedName == qName - } - return false - } - - private fun T.toSourceSetDependent() = mapOf(sourceSetData to this) - - suspend fun parsePackage(packageName: String, psiFiles: List): DPackage = coroutineScope { - val dri = DRI(packageName = packageName) - val packageInfo = psiFiles.singleOrNull { it.name == "package-info.java" } - val documentation = packageInfo?.let { - javadocParser.parseDocumentation(it).toSourceSetDependent() - }.orEmpty() - val annotations = packageInfo?.packageStatement?.annotationList?.annotations - - DPackage( - dri = dri, - functions = emptyList(), - properties = emptyList(), - classlikes = psiFiles.parallelMap { psiFile -> - coroutineScope { - psiFile.classes.asIterable().parallelMap { parseClasslike(it, dri) } - } - }.flatten(), - typealiases = emptyList(), - documentation = documentation, - expectPresentInSet = null, - sourceSets = setOf(sourceSetData), - extra = PropertyContainer.withAll( - annotations?.toList().orEmpty().toListOfAnnotations().toSourceSetDependent().toAnnotations() - ) - ) - } - - private suspend fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = coroutineScope { - with(psi) { - val dri = parent.withClass(name.toString()) - val superMethodsKeys = hashSetOf() - val superMethods = mutableListOf>() - val superFieldsKeys = hashSetOf() - val superFields = mutableListOf>() - methods.asIterable().parallelForEach { superMethodsKeys.add(it.hash) } - - /** - * Caution! This method mutates - * - superMethodsKeys - * - superMethods - * - superFieldsKeys - * - superKeys - */ - /** - * Caution! This method mutates - * - superMethodsKeys - * - superMethods - * - superFieldsKeys - * - superKeys - */ - fun Array.getSuperTypesPsiClasses(): List> { - forEach { type -> - (type as? PsiClassType)?.resolve()?.let { - val definedAt = DRI.from(it) - it.methods.forEach { method -> - val hash = method.hash - if (!method.isConstructor && !superMethodsKeys.contains(hash) && - method.getVisibility() != JavaVisibility.Private - ) { - superMethodsKeys.add(hash) - superMethods.add(Pair(method, definedAt)) - } - } - it.fields.forEach { field -> - val hash = field.hash - if (!superFieldsKeys.contains(hash)) { - superFieldsKeys.add(hash) - superFields.add(Pair(field, definedAt)) - } - } - } - } - return filter { !it.shouldBeIgnored }.mapNotNull { supertypePsi -> - supertypePsi.resolve()?.let { supertypePsiClass -> - val javaClassKind = when { - supertypePsiClass.isInterface -> JavaClassKindTypes.INTERFACE - else -> JavaClassKindTypes.CLASS - } - supertypePsiClass to javaClassKind - } - } - } - - fun traversePsiClassForAncestorsAndInheritedMembers(psiClass: PsiClass): AncestryNode { - val (classes, interfaces) = psiClass.superTypes.getSuperTypesPsiClasses() - .partition { it.second == JavaClassKindTypes.CLASS } - - return AncestryNode( - typeConstructor = GenericTypeConstructor( - DRI.from(psiClass), - psiClass.typeParameters.map { typeParameter -> - TypeParameter( - dri = DRI.from(typeParameter), - name = typeParameter.name.orEmpty(), - extra = typeParameter.annotations() - ) - } - ), - superclass = classes.singleOrNull()?.first?.let(::traversePsiClassForAncestorsAndInheritedMembers), - interfaces = interfaces.map { traversePsiClassForAncestorsAndInheritedMembers(it.first) } - ) - } - - val ancestry: AncestryNode = traversePsiClassForAncestorsAndInheritedMembers(this) - - val (regularFunctions, accessors) = splitFunctionsAndAccessors(psi.fields, psi.methods) - val (regularSuperFunctions, superAccessors) = splitFunctionsAndAccessors( - fields = superFields.map { it.first }.toTypedArray(), - methods = superMethods.map { it.first }.toTypedArray() - ) - - val regularSuperFunctionsKeys = regularSuperFunctions.map { it.hash }.toSet() - val regularSuperFunctionsWithDRI = superMethods.filter { it.first.hash in regularSuperFunctionsKeys } - - val superAccessorsWithDRI = superAccessors.mapValues { (field, methods) -> - val containsJvmField = field.annotations.mapNotNull { it.toAnnotation() }.any { it.isJvmField() } - if (containsJvmField) { - emptyList() - } else { - methods.mapNotNull { method -> superMethods.find { it.first.hash == method.hash } } - } - } - - val overridden = regularFunctions.flatMap { it.findSuperMethods().toList() } - val documentation = javadocParser.parseDocumentation(this).toSourceSetDependent() - val allFunctions = async { - val parsedRegularFunctions = regularFunctions.parallelMapNotNull { - if (!it.isConstructor) parseFunction( - it, - parentDRI = dri - ) else null - } - val parsedSuperFunctions = regularSuperFunctionsWithDRI - .filter { it.first !in overridden } - .parallelMap { parseFunction(it.first, inheritedFrom = it.second) } - - parsedRegularFunctions + parsedSuperFunctions - } - val allFields = async { - val parsedFields = fields.toList().parallelMapNotNull { - parseField(it, accessors[it].orEmpty()) - } - val parsedSuperFields = superFields.parallelMapNotNull { (field, dri) -> - parseFieldWithInheritingAccessors( - field, - superAccessorsWithDRI[field].orEmpty(), - inheritedFrom = dri - ) - } - parsedFields + parsedSuperFields - } - val source = parseSources() - val classlikes = async { innerClasses.asIterable().parallelMap { parseClasslike(it, dri) } } - val visibility = getVisibility().toSourceSetDependent() - val ancestors = (listOfNotNull(ancestry.superclass?.let { - it.typeConstructor.let { typeConstructor -> - TypeConstructorWithKind( - typeConstructor, - JavaClassKindTypes.CLASS - ) - } - }) + ancestry.interfaces.map { - TypeConstructorWithKind( - it.typeConstructor, - JavaClassKindTypes.INTERFACE - ) - }).toSourceSetDependent() - val modifiers = getModifier().toSourceSetDependent() - val implementedInterfacesExtra = - ImplementedInterfaces(ancestry.allImplementedInterfaces().toSourceSetDependent()) - - when { - isAnnotationType -> - DAnnotation( - name = name.orEmpty(), - dri = dri, - documentation = documentation, - expectPresentInSet = null, - sources = source, - functions = allFunctions.await(), - properties = allFields.await(), - classlikes = classlikes.await(), - visibility = visibility, - companion = null, - constructors = parseConstructors(dri), - generics = mapTypeParameters(dri), - sourceSets = setOf(sourceSetData), - isExpectActual = false, - extra = PropertyContainer.withAll( - implementedInterfacesExtra, - annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations() - ) - ) - - isEnum -> DEnum( - dri = dri, - name = name.orEmpty(), - entries = fields.filterIsInstance().map { entry -> - DEnumEntry( - dri = dri.withClass(entry.name).withEnumEntryExtra(), - name = entry.name, - documentation = javadocParser.parseDocumentation(entry).toSourceSetDependent(), - expectPresentInSet = null, - functions = emptyList(), - properties = emptyList(), - classlikes = emptyList(), - sourceSets = setOf(sourceSetData), - extra = PropertyContainer.withAll( - implementedInterfacesExtra, - annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations() - ) - ) - }, - documentation = documentation, - expectPresentInSet = null, - sources = source, - functions = allFunctions.await(), - properties = fields.filter { it !is PsiEnumConstant } - .map { parseField(it, accessors[it].orEmpty()) }, - classlikes = classlikes.await(), - visibility = visibility, - companion = null, - constructors = parseConstructors(dri), - supertypes = ancestors, - sourceSets = setOf(sourceSetData), - isExpectActual = false, - extra = PropertyContainer.withAll( - implementedInterfacesExtra, - annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations() - ) - ) - - isInterface -> DInterface( - dri = dri, - name = name.orEmpty(), - documentation = documentation, - expectPresentInSet = null, - sources = source, - functions = allFunctions.await(), - properties = allFields.await(), - classlikes = classlikes.await(), - visibility = visibility, - companion = null, - generics = mapTypeParameters(dri), - supertypes = ancestors, - sourceSets = setOf(sourceSetData), - isExpectActual = false, - extra = PropertyContainer.withAll( - implementedInterfacesExtra, - annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations() - ) - ) - - else -> DClass( - dri = dri, - name = name.orEmpty(), - constructors = parseConstructors(dri), - functions = allFunctions.await(), - properties = allFields.await(), - classlikes = classlikes.await(), - sources = source, - visibility = visibility, - companion = null, - generics = mapTypeParameters(dri), - supertypes = ancestors, - documentation = documentation, - expectPresentInSet = null, - modifier = modifiers, - sourceSets = setOf(sourceSetData), - isExpectActual = false, - extra = PropertyContainer.withAll( - implementedInterfacesExtra, - annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations(), - ancestry.exceptionInSupertypesOrNull() - ) - ) - } - } - } - - /* - * Parameter `parentDRI` required for substitute package name: - * in the case of synthetic constructor, it will return empty from [DRI.Companion.from]. - */ - private fun PsiClass.parseConstructors(parentDRI: DRI): List { - val constructors = when { - isAnnotationType || isInterface -> emptyArray() - isEnum -> this.constructors - else -> this.constructors.takeIf { it.isNotEmpty() } ?: arrayOf(createDefaultConstructor()) - } - return constructors.map { parseFunction(psi = it, isConstructor = true, parentDRI = parentDRI) } - } - - /** - * PSI doesn't return a default constructor if class doesn't contain an explicit one. - * This method create synthetic constructor - * Visibility modifier is preserved from the class. - */ - private fun PsiClass.createDefaultConstructor(): PsiMethod { - val psiElementFactory = JavaPsiFacade.getElementFactory(project) - val signature = when (val classVisibility = getVisibility()) { - JavaVisibility.Default -> name.orEmpty() - else -> "${classVisibility.name} $name" - } - return psiElementFactory.createConstructor(signature, this) - } - - private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? = - typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() } - ?.let { ExceptionInSupertypes(it.toSourceSetDependent()) } - - private fun parseFunction( - psi: PsiMethod, - isConstructor: Boolean = false, - inheritedFrom: DRI? = null, - parentDRI: DRI? = null, - ): DFunction { - val dri = parentDRI?.let { dri -> - DRI.from(psi).copy(packageName = dri.packageName, classNames = dri.classNames) - } ?: DRI.from(psi) - val docs = psi.getDocumentation() - return DFunction( - dri = dri, - name = psi.name, - isConstructor = isConstructor, - parameters = psi.parameterList.parameters.map { psiParameter -> - DParameter( - dri = dri.copy(target = dri.target.nextTarget()), - name = psiParameter.name, - documentation = DocumentationNode( - listOfNotNull(docs.firstChildOfTypeOrNull { - it.name == psiParameter.name - }) - ).toSourceSetDependent(), - expectPresentInSet = null, - type = getBound(psiParameter.type), - sourceSets = setOf(sourceSetData), - extra = PropertyContainer.withAll( - psiParameter.annotations.toList().toListOfAnnotations().toSourceSetDependent() - .toAnnotations() - ) - ) - }, - documentation = docs.toSourceSetDependent(), - expectPresentInSet = null, - sources = psi.parseSources(), - visibility = psi.getVisibility().toSourceSetDependent(), - type = psi.returnType?.let { getBound(type = it) } ?: Void, - generics = psi.mapTypeParameters(dri), - receiver = null, - modifier = psi.getModifier().toSourceSetDependent(), - sourceSets = setOf(sourceSetData), - isExpectActual = false, - extra = psi.additionalExtras().let { - PropertyContainer.withAll( - inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, - it.toSourceSetDependent().toAdditionalModifiers(), - (psi.annotations.toList() - .toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() - .toAnnotations(), - ObviousMember.takeIf { psi.isObvious(inheritedFrom) }, - psi.throwsList.toDriList().takeIf { it.isNotEmpty() } - ?.let { CheckedExceptions(it.toSourceSetDependent()) } - ) - } - ) - } - - private fun PsiNamedElement.parseSources(): SourceSetDependent { - return when { - // `isPhysical` detects the virtual declarations without real sources. - // Otherwise, `PsiDocumentableSource` initialization will fail: non-physical declarations doesn't have `virtualFile`. - // This check protects from accidentally requesting sources for synthetic / virtual declarations. - isPhysical -> PsiDocumentableSource(this).toSourceSetDependent() - else -> emptyMap() - } - } - - private fun PsiMethod.getDocumentation(): DocumentationNode = - this.takeIf { it is SyntheticElement }?.let { syntheticDocProvider.getDocumentation(it) } - ?: javadocParser.parseDocumentation(this) - - private fun PsiMethod.isObvious(inheritedFrom: DRI? = null): Boolean { - return (this is SyntheticElement && !syntheticDocProvider.isDocumented(this)) - || inheritedFrom?.isObvious() == true - } - - private fun DRI.isObvious(): Boolean { - return packageName == "java.lang" && (classNames == "Object" || classNames == "Enum") - } - - private fun PsiReferenceList.toDriList() = referenceElements.mapNotNull { it?.resolve()?.let { DRI.from(it) } } - - private fun PsiModifierListOwner.additionalExtras() = listOfNotNull( - ExtraModifiers.JavaOnlyModifiers.Static.takeIf { hasModifier(JvmModifier.STATIC) }, - ExtraModifiers.JavaOnlyModifiers.Native.takeIf { hasModifier(JvmModifier.NATIVE) }, - ExtraModifiers.JavaOnlyModifiers.Synchronized.takeIf { hasModifier(JvmModifier.SYNCHRONIZED) }, - ExtraModifiers.JavaOnlyModifiers.StrictFP.takeIf { hasModifier(JvmModifier.STRICTFP) }, - ExtraModifiers.JavaOnlyModifiers.Transient.takeIf { hasModifier(JvmModifier.TRANSIENT) }, - ExtraModifiers.JavaOnlyModifiers.Volatile.takeIf { hasModifier(JvmModifier.VOLATILE) }, - ExtraModifiers.JavaOnlyModifiers.Transitive.takeIf { hasModifier(JvmModifier.TRANSITIVE) } - ).toSet() - - private fun Set.toListOfAnnotations() = map { - if (it !is ExtraModifiers.JavaOnlyModifiers.Static) - Annotations.Annotation(DRI("kotlin.jvm", it.name.toLowerCase().capitalize()), emptyMap()) - else - Annotations.Annotation(DRI("kotlin.jvm", "JvmStatic"), emptyMap()) - } - - /** - * Workaround for getting JvmField Kotlin annotation in PSIs - */ - private fun Collection.findJvmFieldAnnotation(): Annotations.Annotation? { - val anyJvmFieldAnnotation = this.any { - it.qualifiedName == "$JVM_FIELD_PACKAGE_NAME.$JVM_FIELD_CLASS_NAMES" - } - return if (anyJvmFieldAnnotation) { - Annotations.Annotation(DRI(JVM_FIELD_PACKAGE_NAME, JVM_FIELD_CLASS_NAMES), emptyMap()) - } else { - null - } - } - - private fun PsiTypeParameter.annotations(): PropertyContainer = this.annotations.toList().toListOfAnnotations().annotations() - private fun PsiType.annotations(): PropertyContainer = this.annotations.toList().toListOfAnnotations().annotations() - - private fun List.annotations(): PropertyContainer = - this.takeIf { it.isNotEmpty() }?.let { annotations -> - PropertyContainer.withAll(annotations.toSourceSetDependent().toAnnotations()) - } ?: PropertyContainer.empty() - - private fun getBound(type: PsiType): Bound { - //We would like to cache most of the bounds since it is not common to annotate them, - //but if this is the case, we treat them as 'one of' - fun PsiType.cacheBoundIfHasNoAnnotation(f: (List) -> Bound): Bound { - val annotations = this.annotations.toList().toListOfAnnotations() - return if (annotations.isNotEmpty()) f(annotations) - else cachedBounds.getOrPut(canonicalText) { - f(annotations) - } - } - - return when (type) { - is PsiClassType -> - type.resolve()?.let { resolved -> - when { - resolved.qualifiedName == "java.lang.Object" -> type.cacheBoundIfHasNoAnnotation { annotations -> JavaObject(annotations.annotations()) } - resolved is PsiTypeParameter -> { - TypeParameter( - dri = DRI.from(resolved), - name = resolved.name.orEmpty(), - extra = type.annotations() - ) - } - - Regex("kotlin\\.jvm\\.functions\\.Function.*").matches(resolved.qualifiedName ?: "") || - Regex("java\\.util\\.function\\.Function.*").matches( - resolved.qualifiedName ?: "" - ) -> FunctionalTypeConstructor( - DRI.from(resolved), - type.parameters.map { getProjection(it) }, - extra = type.annotations() - ) - - else -> { - // cache types that have no annotation and no type parameter - // since we cache only by name and type parameters depend on context - val typeParameters = type.parameters.map { getProjection(it) } - if (typeParameters.isEmpty()) - type.cacheBoundIfHasNoAnnotation { annotations -> - GenericTypeConstructor( - DRI.from(resolved), - typeParameters, - extra = annotations.annotations() - ) - } - else - GenericTypeConstructor( - DRI.from(resolved), - typeParameters, - extra = type.annotations() - ) - } - } - } ?: UnresolvedBound(type.presentableText, type.annotations()) - - is PsiArrayType -> GenericTypeConstructor( - DRI("kotlin", "Array"), - listOf(getProjection(type.componentType)), - extra = type.annotations() - ) - - is PsiPrimitiveType -> if (type.name == "void") Void - else type.cacheBoundIfHasNoAnnotation { annotations -> PrimitiveJavaType(type.name, annotations.annotations()) } - else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser") - } - } - - - private fun getVariance(type: PsiWildcardType): Projection = when { - type.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 { - fun mapBounds(bounds: Array): List = - if (bounds.isEmpty()) emptyList() else bounds.mapNotNull { - (it as? PsiClassType)?.let { classType -> Nullable(getBound(classType)) } - } - return typeParameters.map { type -> - DTypeParameter( - dri = dri.copy(target = dri.target.nextTarget()), - name = type.name.orEmpty(), - presentableName = null, - documentation = javadocParser.parseDocumentation(type).toSourceSetDependent(), - expectPresentInSet = null, - bounds = mapBounds(type.bounds), - sourceS