aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/transformers/psi
diff options
context:
space:
mode:
authorBłażej Kardyś <bkardys@virtuslab.com>2020-02-26 15:51:07 +0100
committerPaweł Marks <Kordyjan@users.noreply.github.com>2020-02-27 10:51:51 +0100
commitb62126328f0778abe21d3334f5a713086cb3d15e (patch)
tree7b20dba4051626b0646a57df82f7130627a349ce /plugins/base/src/main/kotlin/transformers/psi
parent3aadd4c85e55ab8321bd3230ffd975cc85e394a8 (diff)
downloaddokka-b62126328f0778abe21d3334f5a713086cb3d15e.tar.gz
dokka-b62126328f0778abe21d3334f5a713086cb3d15e.tar.bz2
dokka-b62126328f0778abe21d3334f5a713086cb3d15e.zip
Adding psi parsing for new model
Diffstat (limited to 'plugins/base/src/main/kotlin/transformers/psi')
-rw-r--r--plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt241
1 files changed, 193 insertions, 48 deletions
diff --git a/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt
index 364cb34b..da06e621 100644
--- a/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt
@@ -1,5 +1,7 @@
package org.jetbrains.dokka.base.transformers.psi
+import com.intellij.lang.jvm.JvmModifier
+import com.intellij.lang.jvm.types.JvmReferenceType
import com.intellij.psi.*
import org.jetbrains.dokka.JavadocParser
import org.jetbrains.dokka.links.Callable
@@ -7,7 +9,11 @@ import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.JavaClassReference
import org.jetbrains.dokka.links.withClass
import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.Annotation
+import org.jetbrains.dokka.model.Enum
import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.model.InheritedFunction
+import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.pages.PlatformData
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.transformers.psi.PsiToDocumentableTranslator
@@ -27,16 +33,22 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
platformData,
context.logger
)
- return Module(moduleName,
+ return Module(
+ moduleName,
psiFiles.map { psiFile ->
val dri = DRI(packageName = psiFile.packageName)
Package(
dri,
emptyList(),
emptyList(),
- psiFile.classes.map { docParser.parseClass(it, dri) }
+ psiFile.classes.map { docParser.parseClasslike(it, dri) },
+ emptyList(),
+ PlatformDependent.empty(),
+ listOf(platformData)
)
- }
+ },
+ PlatformDependent.empty(),
+ listOf(platformData)
)
}
@@ -47,11 +59,6 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
private val javadocParser: JavadocParser = JavadocParser(logger)
- private fun getComment(psi: PsiNamedElement): List<PlatformInfo> {
- val comment = javadocParser.parseDocumentation(psi)
- return listOf(BasePlatformInfo(comment, listOf(platformData)))
- }
-
private fun PsiModifierListOwner.getVisibility() = modifierList?.children?.toList()?.let { ml ->
when {
ml.any { it.text == PsiKeyword.PUBLIC } -> Visibilities.PUBLIC
@@ -60,69 +67,203 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
}
} ?: Visibilities.PRIVATE
- 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
+ private val PsiMethod.hash: Int
+ get() = "$returnType $name$parameterList".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.toPlatformDependant() =
+ PlatformDependent(mapOf(platformData to this))
+
+ fun parseClasslike(psi: PsiClass, parent: DRI): Classlike = with(psi) {
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)
+ val ancestorsSet = hashSetOf<DRI>()
+ val superMethodsKeys = hashSetOf<Int>()
+ val superMethods = mutableListOf<PsiMethod>()
+ methods.forEach { superMethodsKeys.add(it.hash) }
+ fun addAncestors(element: PsiClass) {
+ ancestorsSet.add(element.toDRI())
+ element.interfaces.forEach(::addAncestors)
+ element.superClass?.let(::addAncestors)
+ }
+
+ fun parseSupertypes(superTypes: Array<PsiClassType>) {
+ superTypes.forEach { type ->
+ (type as? PsiClassType)?.takeUnless { type.shouldBeIgnored }?.resolve()?.let {
+ it.methods.forEach { method ->
+ val hash = method.hash
+ if (!method.isConstructor && !superMethodsKeys.contains(hash) &&
+ method.getVisibility() != Visibilities.PRIVATE
+ ) {
+ superMethodsKeys.add(hash)
+ superMethods.add(method)
+ }
+ }
+ addAncestors(it)
+ parseSupertypes(it.superTypes)
+ }
+ }
+ }
+ parseSupertypes(superTypes)
+ val documentation = javadocParser.parseDocumentation(this).toPlatformDependant()
+ val allFunctions = methods.mapNotNull { if (!it.isConstructor) parseFunction(it, dri) else null } +
+ superMethods.map { parseFunction(it, dri, isInherited = true) }
+ val source = PsiDocumentableSource(this).toPlatformDependant()
+ val classlikes = innerClasses.map { parseClasslike(it, dri) }
+ val visibility = getVisibility().toPlatformDependant()
+ val ancestors = ancestorsSet.toList().toPlatformDependant()
+ return when {
+ isAnnotationType ->
+ Annotation(
+ name.orEmpty(),
+ dri,
+ documentation,
+ source,
+ allFunctions,
+ fields.mapNotNull { parseField(it, dri) },
+ classlikes,
+ visibility,
+ null,
+ constructors.map { parseFunction(it, dri, true) },
+ listOf(platformData)
+ )
+ isEnum -> Enum(
+ dri,
+ name.orEmpty(),
+ fields.filterIsInstance<PsiEnumConstant>().map { entry ->
+ EnumEntry(
+ dri.withClass("$name.${entry.name}"),
+ entry.name.orEmpty(),
+ javadocParser.parseDocumentation(entry).toPlatformDependant(),
+ emptyList(),
+ emptyList(),
+ emptyList(),
+ listOf(platformData)
+ )
+ },
+ documentation,
+ source,
+ allFunctions,
+ fields.filter { it !is PsiEnumConstant }.map { parseField(it, dri) },
+ classlikes,
+ visibility,
+ null,
+ constructors.map { parseFunction(it, dri, true) },
+ ancestors,
+ listOf(platformData)
+ )
+ isInterface -> Interface(
+ dri,
+ name.orEmpty(),
+ documentation,
+ source,
+ allFunctions,
+ fields.mapNotNull { parseField(it, dri) },
+ classlikes,
+ visibility,
+ null,
+ mapTypeParameters(dri),
+ ancestors,
+ listOf(platformData)
+ )
+ else -> Class(
+ dri,
+ name.orEmpty(),
+ constructors.map { parseFunction(it, dri, true) },
+ allFunctions,
+ fields.mapNotNull { parseField(it, dri) },
+ classlikes,
+ source,
+ visibility,
+ null,
+ mapTypeParameters(dri),
+ ancestors,
+ documentation,
+ getModifier(),
+ listOf(platformData)
+ )
}
- }*/
- val inherited = emptyList<DRI>() //listOf(psi.superClass) + psi.interfaces // TODO DRIs of inherited
- val actual = getComment(psi).map { ClassPlatformInfo(it, inherited) }
-
- return Class(
- dri = dri,
- name = name.orEmpty(),
- kind = kind,
- constructors = constructors.map { parseFunction(it, dri, true) },
- functions = methods.mapNotNull { if (!it.isConstructor) parseFunction(it, dri) else null },
- properties = fields.mapNotNull { parseField(it, dri) },
- classlikes = innerClasses.map { parseClass(it, dri) },
- expected = null,
- actual = actual,
- extra = mutableSetOf(),
- visibility = mapOf(platformData to psi.getVisibility())
- )
}
- private fun parseFunction(psi: PsiMethod, parent: DRI, isConstructor: Boolean = false): Function {
+ private fun parseFunction(
+ psi: PsiMethod,
+ parent: DRI,
+ isConstructor: Boolean = false,
+ isInherited: 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,
+ javadocParser.parseDocumentation(psiParameter).toPlatformDependant(),
JavaTypeWrapper(psiParameter.type),
- null,
- getComment(psi)
+ listOf(platformData)
)
},
+ javadocParser.parseDocumentation(psi).toPlatformDependant(),
+ PsiDocumentableSource(psi).toPlatformDependant(),
+ psi.getVisibility().toPlatformDependant(),
+ psi.returnType?.let { JavaTypeWrapper(type = it) } ?: JavaTypeWrapper.VOID,
+ psi.mapTypeParameters(dri),
null,
- getComment(psi),
- visibility = mapOf(platformData to psi.getVisibility())
+ psi.getModifier(),
+ listOf(platformData),
+ PropertyContainer.empty<Function>() + InheritedFunction(
+ isInherited
+ )
+
)
}
+ private fun PsiModifierListOwner.getModifier() = when {
+ hasModifier(JvmModifier.ABSTRACT) -> WithAbstraction.Modifier.Abstract
+ hasModifier(JvmModifier.STATIC) -> WithAbstraction.Modifier.Static
+ hasModifier(JvmModifier.FINAL) -> WithAbstraction.Modifier.Final
+ else -> null
+ }
+
+ private fun PsiTypeParameterListOwner.mapTypeParameters(dri: DRI): List<TypeParameter> {
+ fun mapProjections(bounds: Array<JvmReferenceType>) =
+ if (bounds.isEmpty()) listOf(Projection.Star) else bounds.mapNotNull {
+ (it as PsiClassType).let { classType ->
+ Projection.Nullable(Projection.TypeConstructor(classType.resolve()!!.toDRI(), emptyList()))
+ }
+ }
+ return typeParameters.mapIndexed { index, type ->
+ TypeParameter(
+ dri.copy(genericTarget = index),
+ type.name.orEmpty(),
+ javadocParser.parseDocumentation(type).toPlatformDependant(),
+ mapProjections(type.bounds),
+ listOf(platformData)
+ )
+ }
+ }
+
+ private fun PsiQualifiedNamedElement.toDRI() =
+ DRI(qualifiedName.orEmpty().substringBeforeLast('.', ""), name)
+
private fun parseField(psi: PsiField, parent: DRI): Property {
val dri = parent.copy(
callable = Callable(
@@ -134,11 +275,15 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
return Property(
dri,
psi.name!!, // TODO: Investigate if this is indeed nullable
+ javadocParser.parseDocumentation(psi).toPlatformDependant(),
+ PsiDocumentableSource(psi).toPlatformDependant(),
+ psi.getVisibility().toPlatformDependant(),
+ JavaTypeWrapper(psi.type),
+ null,
null,
null,
- getComment(psi),
- accessors = emptyList(),
- visibility = mapOf(platformData to psi.getVisibility())
+ psi.getModifier(),
+ listOf(platformData)
)
}
}