diff options
-rw-r--r-- | core/src/main/kotlin/CoreExtensions.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/DokkaGenerator.kt | 30 | ||||
-rw-r--r-- | core/src/main/kotlin/Java/JavadocParser.kt | 373 | ||||
-rw-r--r-- | core/src/main/kotlin/links/DRI.kt | 5 | ||||
-rw-r--r-- | core/src/main/kotlin/model/Documentable.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/pages/PageContentBuilder.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/DefaultExtensions.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt | 166 | ||||
-rw-r--r-- | core/src/main/kotlin/transformers/psi/PsiToDocumentationTranslator.kt | 14 |
9 files changed, 593 insertions, 3 deletions
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt index c1871118..46b241a7 100644 --- a/core/src/main/kotlin/CoreExtensions.kt +++ b/core/src/main/kotlin/CoreExtensions.kt @@ -10,6 +10,7 @@ import org.jetbrains.dokka.transformers.documentation.DocumentationNodeMerger import org.jetbrains.dokka.transformers.documentation.DocumentationNodeTransformer import org.jetbrains.dokka.transformers.documentation.DocumentationToPageTranslator import org.jetbrains.dokka.transformers.pages.PageNodeTransformer +import org.jetbrains.dokka.transformers.psi.PsiToDocumentationTranslator import kotlin.reflect.KProperty @@ -19,6 +20,7 @@ import kotlin.reflect.KProperty */ object CoreExtensions { val descriptorToDocumentationTranslator by coreExtension<DescriptorToDocumentationTranslator>() + val psiToDocumentationTranslator by coreExtension<PsiToDocumentationTranslator>() val documentationMerger by coreExtension<DocumentationNodeMerger>() val documentationTransformer by coreExtension<DocumentationNodeTransformer>() val commentsToContentConverter by coreExtension<CommentsToContentConverter>() diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index 036cbfda..350ee5df 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -1,5 +1,8 @@ package org.jetbrains.dokka +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.PsiManager import org.jetbrains.dokka.analysis.AnalysisEnvironment import org.jetbrains.dokka.analysis.DokkaResolutionFacade import org.jetbrains.dokka.model.Module @@ -8,11 +11,13 @@ import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.single import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity 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.cli.jvm.config.JavaSourceRoot import org.jetbrains.kotlin.utils.PathUtil import java.io.File @@ -64,7 +69,8 @@ class DokkaGenerator( fun createDocumentationModels( platforms: Map<PlatformData, EnvironmentAndFacade>, context: DokkaContext - ) = platforms.map { (pdata, _) -> translateDescriptors(pdata, context) } + ) = platforms.map { (pdata, _) -> translateDescriptors(pdata, context) } + + platforms.map { (pdata, _) -> translatePsi(pdata, context) } fun mergeDocumentationModels( modulesFromPlatforms: List<Module>, @@ -123,6 +129,28 @@ class DokkaGenerator( .invoke(platformData.name, packageFragments, platformData, context) } + private fun translatePsi(platformData: PlatformData, context: DokkaContext): Module { + val (environment, _) = context.platforms.getValue(platformData) + + val sourceRoots = environment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) + ?.filterIsInstance<JavaSourceRoot>() + ?.map { it.file } + ?: listOf() + val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file") + + val psiFiles = sourceRoots.map { sourceRoot -> + sourceRoot.absoluteFile.walkTopDown().mapNotNull { + localFileSystem.findFileByPath(it.path)?.let { vFile -> + PsiManager.getInstance(environment.project).findFile(vFile) as? PsiJavaFile + } + }.toList() + }.flatten() + + return context.single(CoreExtensions.psiToDocumentationTranslator) + .invoke(psiFiles, platformData, context) + + } + private class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector { override fun clear() { seenErrors = false diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt new file mode 100644 index 00000000..5058634a --- /dev/null +++ b/core/src/main/kotlin/Java/JavadocParser.kt @@ -0,0 +1,373 @@ +package org.jetbrains.dokka + +import com.intellij.psi.* +import com.intellij.psi.impl.source.tree.JavaDocElementType +import com.intellij.psi.javadoc.* +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.containers.isNullOrEmpty +import kotlinx.html.P +import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.utils.keysToMap +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import org.jsoup.nodes.Node +import org.jsoup.nodes.TextNode +import java.net.URI + +interface JavaDocumentationParser { + fun parseDocumentation(element: PsiNamedElement): DocumentationNode +} + +class JavadocParser( + private val logger: DokkaLogger +) : JavaDocumentationParser { + + override fun parseDocumentation(element: PsiNamedElement): DocumentationNode { + val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return DocumentationNode(emptyList()) + val nodes = + convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element) + return DocumentationNode(nodes.map { Description(it) }) + /*val firstParagraphContents = nodes.takeWhile { it !is ContentParagraph } + val firstParagraph = ContentParagraph() + if (firstParagraphContents.isNotEmpty()) { + firstParagraphContents.forEach { firstParagraph.append(it) } + result.add(firstParagraph) + } + + result.appendAll(nodes.drop(firstParagraphContents.size)) + + if (element is PsiMethod) { + val tagsByName = element.searchInheritedTags() + for ((tagName, tags) in tagsByName) { + for ((tag, context) in tags) { + val section = result.addSection(javadocSectionDisplayName(tagName), tag.getSubjectName()) + val signature = signatureProvider.signature(element) + when (tagName) { + "param" -> { + section.appendTypeElement(signature) { + it.details + .find { node -> node.kind == NodeKind.Parameter && node.name == tag.getSubjectName() } + ?.detailOrNull(NodeKind.Type) + } + } + "return" -> { + section.appendTypeElement(signature) { it.detailOrNull(NodeKind.Type) } + } + } + section.appendAll(convertJavadocElements(tag.contentElements(), context)) + } + } + } + + docComment.tags.forEach { tag -> + when (tag.name) { + "see" -> result.convertSeeTag(tag) + "deprecated" -> { + deprecatedContent = Content().apply { + appendAll(convertJavadocElements(tag.contentElements(), element)) + } + } + in tagsToInherit -> {} + else -> { + val subjectName = tag.getSubjectName() + val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName) + + section.appendAll(convertJavadocElements(tag.contentElements(), element)) + } + } + } + return JavadocParseResult(result, deprecatedContent)*/ + } + + private val tagsToInherit = setOf("param", "return", "throws") + + private data class TagWithContext(val tag: PsiDocTag, val context: PsiNamedElement) +/* + private fun PsiMethod.searchInheritedTags(): Map<String, Collection<TagWithContext>> { + + val output = tagsToInherit.keysToMap { mutableMapOf<String?, TagWithContext>() } + + fun recursiveSearch(methods: Array<PsiMethod>) { + for (method in methods) { + recursiveSearch(method.findSuperMethods()) + } + for (method in methods) { + for (tag in method.docComment?.tags.orEmpty()) { + if (tag.name in tagsToInherit) { + output[tag.name]!![tag.getSubjectName()] = TagWithContext(tag, method) + } + } + } + } + + recursiveSearch(arrayOf(this)) + return output.mapValues { it.value.values } + } +*/ + + private fun PsiDocTag.contentElements(): Iterable<PsiElement> { + val tagValueElements = children + .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME } + .dropWhile { it is PsiWhiteSpace } + .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS } + return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements + } + + private fun convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement): List<DocTag> { + val doc = Jsoup.parse(expandAllForElements(elements, element)) + return doc.body().childNodes().mapNotNull { convertHtmlNode(it) } + } + + private fun expandAllForElements(elements: Iterable<PsiElement>, element: PsiNamedElement): String { + val htmlBuilder = StringBuilder() + elements.forEach { + if (it is PsiInlineDocTag) { + htmlBuilder.append(convertInlineDocTag(it, element)) + } else { + htmlBuilder.append(it.text) + } + } + return htmlBuilder.toString().trim() + } + + private fun convertHtmlNode(node: Node, insidePre: Boolean = false): DocTag? = when (node) { + is TextNode -> Text(body = if (insidePre) node.wholeText else node.text()) + is Element -> createBlock(node) + else -> null + } + + private fun createBlock(element: Element): DocTag { + val children = element.childNodes().mapNotNull { convertHtmlNode(it) } + return when (element.tagName()) { + "p" -> P(children) + "b" -> B(children) + "strong" -> Strong(children) + "i" -> I(children) + "em" -> Em(children) +// "s", "del" -> ContentStrikethrough() + "code" -> Code(children) + "pre" -> Pre(children) + "ul" -> Ul(children) + "ol" -> Ol(children) + "li" -> Li(children) +// "a" -> createLink(element) +// "br" -> ContentBlock().apply { hardLineBreak() } + else -> Text(body = element.ownText()) + } + } +/* + + private fun createLink(element: Element): DocTag { + return when { + element.hasAttr("docref") -> { + val docref = element.attr("docref") + ContentNodeLazyLink(docref) { refGraph.lookupOrWarn(docref, logger) } + } + element.hasAttr("href") -> { + val href = element.attr("href") + + val uri = try { + URI(href) + } catch (_: Exception) { + null + } + + if (uri?.isAbsolute == false) { + ContentLocalLink(href) + } else { + ContentExternalLink(href) + } + } + element.hasAttr("name") -> { + ContentBookmark(element.attr("name")) + } + else -> ContentBlock() + } + } + + + private fun convertSeeTag(tag: PsiDocTag) { + val linkElement = tag.linkElement() ?: return + val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null) + + val valueElement = tag.referenceElement() + val externalLink = resolveExternalLink(valueElement) + val text = ContentText(linkElement.text) + + val linkSignature by lazy { resolveInternalLink(valueElement) } + val node = when { + externalLink != null -> { + val linkNode = ContentExternalLink(externalLink) + linkNode.append(text) + linkNode + } + linkSignature != null -> { + val linkNode = + ContentNodeLazyLink( + (tag.valueElement ?: linkElement).text + ) { refGraph.lookupOrWarn(linkSignature!!, logger) } + linkNode.append(text) + linkNode + } + else -> text + } + seeSection.append(node) + } +*/ + private fun convertInlineDocTag(tag: PsiInlineDocTag, element: PsiNamedElement) = when (tag.name) { + "link", "linkplain" -> { + val valueElement = tag.referenceElement() + val externalLink = resolveExternalLink(valueElement) + val linkSignature by lazy { resolveInternalLink(valueElement) } + if (externalLink != null || linkSignature != null) { + val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text + val linkTarget = if (externalLink != null) "href=\"$externalLink\"" else "docref=\"$linkSignature\"" + val link = "<a $linkTarget>$labelText</a>" + if (tag.name == "link") "<code>$link</code>" else link + } else if (valueElement != null) { + valueElement.text + } else { + "" + } + } + "code", "literal" -> { + val text = StringBuilder() + tag.dataElements.forEach { text.append(it.text) } + val escaped = text.toString().trimStart() + if (tag.name == "code") "<code>$escaped</code>" else escaped + } + "inheritDoc" -> { + val result = (element as? PsiMethod)?.let { + // @{inheritDoc} is only allowed on functions + val parent = tag.parent + when (parent) { + is PsiDocComment -> element.findSuperDocCommentOrWarn() + is PsiDocTag -> element.findSuperDocTagOrWarn(parent) + else -> null + } + } + result ?: tag.text + } + else -> tag.text + } + + private fun PsiDocTag.referenceElement(): PsiElement? = + linkElement()?.let { + if (it.node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) { + PsiTreeUtil.findChildOfType(it, PsiJavaCodeReferenceElement::class.java) + } else { + it + } + } + + private fun PsiDocTag.linkElement(): PsiElement? = + valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace } + + private fun resolveExternalLink(valueElement: PsiElement?): String? { + /*val target = valueElement?.reference?.resolve() + if (target != null) { + return externalDocumentationLinkResolver.buildExternalDocumentationLink(target) + }*/ + return null + } + + private fun resolveInternalLink(valueElement: PsiElement?): String? { + /*val target = valueElement?.reference?.resolve() + if (target != null) { + return signatureProvider.signature(target) + }*/ + return null + } + + fun PsiDocTag.getSubjectName(): String? { + if (name == "param" || name == "throws" || name == "exception") { + return valueElement?.text + } + return null + } + + private fun PsiMethod.findSuperDocCommentOrWarn(): String { + val method = findFirstSuperMethodWithDocumentation(this) + if (method != null) { + val descriptionElements = method.docComment?.descriptionElements?.dropWhile { + it.text.trim().isEmpty() + } ?: return "" + + return expandAllForElements(descriptionElements, method) + } + logger.warn("No docs found on supertype with {@inheritDoc} method ${this.name} in ${this.containingFile.name}}") + return "" + } + + + private fun PsiMethod.findSuperDocTagOrWarn(elementToExpand: PsiDocTag): String { + val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, this) + + if (result != null) { + val (method, tag) = result + + val contentElements = tag.contentElements().dropWhile { it.text.trim().isEmpty() } + + val expandedString = expandAllForElements(contentElements, method) + + return expandedString + } + logger.warn("No docs found on supertype for @${elementToExpand.name} ${elementToExpand.getSubjectName()} with {@inheritDoc} method ${this.name} in ${this.containingFile.name}}") + return "" + } + + private fun findFirstSuperMethodWithDocumentation(current: PsiMethod): PsiMethod? { + val superMethods = current.findSuperMethods() + for (method in superMethods) { + val docs = method.docComment?.descriptionElements?.dropWhile { it.text.trim().isEmpty() } + if (!docs.isNullOrEmpty()) { + return method + } + } + for (method in superMethods) { + val result = findFirstSuperMethodWithDocumentation(method) + if (result != null) { + return result + } + } + + return null + } + + private fun findFirstSuperMethodWithDocumentationforTag(elementToExpand: PsiDocTag, current: PsiMethod): Pair<PsiMethod, PsiDocTag>? { + val superMethods = current.findSuperMethods() + val mappedFilteredTags = superMethods.map { + it to it.docComment?.tags?.filter { it.name == elementToExpand.name } + } + + for ((method, tags) in mappedFilteredTags) { + tags ?: continue + for (tag in tags) { + val (tagSubject, elementSubject) = when (tag.name) { + "throws" -> { + // match class names only for throws, ignore possibly fully qualified path + // TODO: Always match exactly here + tag.getSubjectName()?.split(".")?.last() to elementToExpand.getSubjectName()?.split(".")?.last() + } + else -> { + tag.getSubjectName() to elementToExpand.getSubjectName() + } + } + + if (tagSubject == elementSubject) { + return method to tag + } + } + } + + for (method in superMethods) { + val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, method) + if (result != null) { + return result + } + } + return null + } + +} diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt index 0fe2900b..404813fa 100644 --- a/core/src/main/kotlin/links/DRI.kt +++ b/core/src/main/kotlin/links/DRI.kt @@ -110,6 +110,11 @@ sealed class TypeReference { } } +data class JavaClassReference(val name: String): TypeReference() { + override val isNullable = true + override fun toString(): String = name +} + data class TypeParam(val bounds: List<TypeReference>, override val isNullable: Boolean) : TypeReference() data class TypeConstructor( diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index ac0b41d9..3f50667a 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -152,7 +152,7 @@ private fun String.shorten(maxLength: Int) = lineSequence().first().let { interface TypeWrapper { val constructorFqName: String? val constructorNamePathSegments: List<String> - val arguments: List<KotlinTypeWrapper> + val arguments: List<TypeWrapper> val dri: DRI? } interface ClassKind diff --git a/core/src/main/kotlin/pages/PageContentBuilder.kt b/core/src/main/kotlin/pages/PageContentBuilder.kt index cc53586e..25ddc2f1 100644 --- a/core/src/main/kotlin/pages/PageContentBuilder.kt +++ b/core/src/main/kotlin/pages/PageContentBuilder.kt @@ -168,7 +168,7 @@ private fun PageContentBuilder.type(t: TypeWrapper) { link(t.constructorNamePathSegments.last(), t.dri!!) else (this as? DefaultPageContentBuilder)?.let { logger.error("type $t cannot be resolved") - text("???") + text(t.toString()) } list(t.arguments, prefix = "<", suffix = ">") { type(it) diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt index b3ff4248..91ab9cb8 100644 --- a/core/src/main/kotlin/plugability/DefaultExtensions.kt +++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt @@ -8,6 +8,7 @@ import org.jetbrains.dokka.resolvers.DefaultLocationProviderFactory import org.jetbrains.dokka.transformers.descriptors.DefaultDescriptorToDocumentationTranslator import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationNodeMerger import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationToPageTranslator +import org.jetbrains.dokka.transformers.psi.DefaultPsiToDocumentationTranslator internal object DefaultExtensions { @@ -20,6 +21,7 @@ internal object DefaultExtensions { internal fun <T : Any, E : ExtensionPoint<T>> get(point: E, fullContext: DokkaContext): List<T> = when (point) { CoreExtensions.descriptorToDocumentationTranslator -> DefaultDescriptorToDocumentationTranslator + CoreExtensions.psiToDocumentationTranslator -> DefaultPsiToDocumentationTranslator CoreExtensions.documentationMerger -> DefaultDocumentationNodeMerger CoreExtensions.commentsToContentConverter -> converter.get(fullContext) CoreExtensions.documentationToPageTranslator -> DefaultDocumentationToPageTranslator diff --git a/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt new file mode 100644 index 00000000..d3ad4526 --- /dev/null +++ b/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt @@ -0,0 +1,166 @@ +package org.jetbrains.dokka.transformers.psi + +import com.intellij.psi.* +import com.intellij.psi.impl.source.PsiClassReferenceType +import org.jetbrains.dokka.JavadocParser +import org.jetbrains.dokka.links.* +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.DokkaLogger + +object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator { + + override fun invoke( + psiFiles: List<PsiJavaFile>, + platformData: PlatformData, + context: DokkaContext + ): Module { + val docParser = DokkaPsiParser(platformData, context.logger) + return Module( "JavaModule", + psiFiles.map { psiFile -> + val dri = DRI(packageName = psiFile.packageName) + Package( + dri, + emptyList(), + emptyList(), + psiFile.classes.map { docParser.parseClass(it, dri) } + ) + } + ) + } + + class DokkaPsiParser( + private val platformData: PlatformData, + logger: DokkaLogger + ) { + + private val javadocParser: JavadocParser = JavadocParser(logger) + + private fun getComment(psi: PsiNamedElement): List<PlatformInfo> { + val comment = javadocParser.parseDocumentation(psi) + return listOf(BasePlatformInfo(comment, listOf(platformData))) + } + + fun parseClass(psi: PsiClass, parent: DRI): Class = with(psi) { + val kind = when { + isAnnotationType -> JavaClassKindTypes.ANNOTATION_CLASS + isInterface -> JavaClassKindTypes.INTERFACE + isEnum -> JavaClassKindTypes.ENUM_CLASS + else -> JavaClassKindTypes.CLASS + } + val dri = parent.withClass(name.toString()) + /*superTypes.filter { !ignoreSupertype(it) }.forEach { + node.appendType(it, NodeKind.Supertype) + val superClass = it.resolve() + if (superClass != null) { + link(superClass, node, RefKind.Inheritor) + } + }*/ + return Class( + dri, + name.orEmpty(), + kind, + constructors.map { parseFunction(it, dri, true) }, + methods.mapNotNull { if (!it.isConstructor) parseFunction(it, dri) else null }, + fields.mapNotNull { parseField(it, dri) }, + innerClasses.map { parseClass(it, dri) }, + null, + emptyList(), + mutableSetOf() + ) + } + + private fun parseFunction(psi: PsiMethod, parent: DRI, isConstructor: Boolean = false): Function { + val dri = parent.copy(callable = Callable( + psi.name, + JavaClassReference(psi.containingClass?.name.orEmpty()), + psi.parameterList.parameters.map { parameter -> + JavaClassReference(parameter.type.canonicalText) + } + ) + ) + return Function( + dri, + if (isConstructor) "<init>" else psi.name, + psi.returnType?.let { JavaTypeWrapper(type = it) }, + isConstructor, + null, + psi.parameterList.parameters.mapIndexed { index, psiParameter -> + Parameter( + dri.copy(target = index + 1), + psiParameter.name, + JavaTypeWrapper(psiParameter.type), + getComment(psi) + ) + }, + null, + getComment(psi) + ) + } + + private fun parseField(psi: PsiField, parent: DRI): Property { + val dri = parent.copy( + callable = Callable( + psi.name, + JavaClassReference(psi.containingClass?.name.orEmpty()), + emptyList() + ) + ) + return Property( + dri, + psi.name, + null, + null, + getComment(psi) + ) + } + } +} + +enum class JavaClassKindTypes : ClassKind { + CLASS, + INTERFACE, + ENUM_CLASS, + ENUM_ENTRY, + ANNOTATION_CLASS; +} + +class JavaTypeWrapper( + type: PsiType +) : TypeWrapper { + + override val constructorFqName: String? + override val constructorNamePathSegments: List<String> + override val arguments: List<JavaTypeWrapper> + override val dri: DRI? + + init { + if (type is PsiClassReferenceType) { + val resolved = type.resolve() + constructorFqName = resolved?.qualifiedName + constructorNamePathSegments = resolved?.qualifiedName?.split('.') ?: emptyList() + arguments = type.parameters.mapNotNull { + if (it is PsiClassReferenceType) JavaTypeWrapper(it) else null + } + dri = fromPsi(type) + } else { + type as PsiPrimitiveType + constructorFqName = type.name + constructorNamePathSegments = type.name.split('.') + arguments = emptyList() + dri = null + } + } + + private fun fromPsi(type: PsiClassReferenceType): DRI { + val className = type.className + val pkg = type.canonicalText.removeSuffix(className).removeSuffix(".") + return DRI(packageName = pkg, classNames = className) + } + + override fun toString(): String { + return constructorFqName.orEmpty() + } +}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/psi/PsiToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/psi/PsiToDocumentationTranslator.kt new file mode 100644 index 00000000..5a1209b1 --- /dev/null +++ b/core/src/main/kotlin/transformers/psi/PsiToDocumentationTranslator.kt @@ -0,0 +1,14 @@ +package org.jetbrains.dokka.transformers.psi + +import com.intellij.psi.PsiJavaFile +import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.plugability.DokkaContext + +interface PsiToDocumentationTranslator { + fun invoke( + psiFiles: List<PsiJavaFile>, + platformData: PlatformData, + context: DokkaContext + ): Module +} |