From e22e466485042b129c5272a85cb27e56430f897f Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Mon, 4 Dec 2017 17:58:45 +0300 Subject: [PATCH] Uast: making `AbstractKotlinUClass` not inherit from `AbstractJavaUClass` --- .../uast/kotlin/KotlinAbstractUElement.kt | 9 ++++ .../uast/kotlin/declarations/KotlinUClass.kt | 47 ++++++++++++------- .../uast-kotlin/testData/ClassAnnotation.kt | 22 +++++++++ .../testData/ClassAnnotation.log.txt | 30 ++++++++++++ .../testData/ClassAnnotation.render.txt | 23 +++++++++ .../testData/SimpleScript.render.txt | 2 +- .../UnexpectedContainerException.types.txt | 2 +- .../tests/SimpleKotlinRenderLogTest.kt | 3 ++ 8 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 plugins/uast-kotlin/testData/ClassAnnotation.kt create mode 100644 plugins/uast-kotlin/testData/ClassAnnotation.log.txt create mode 100644 plugins/uast-kotlin/testData/ClassAnnotation.render.txt diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt index fb812f277a2..d20c28e475c 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt @@ -18,6 +18,7 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration import org.jetbrains.kotlin.asJava.toLightGetter import org.jetbrains.kotlin.asJava.toLightSetter import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget @@ -40,6 +41,14 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : UEle val psi = psi var parent = psi?.parent ?: psi?.containingFile + if (psi is KtLightClassForLocalDeclaration) { + val originParent = psi.kotlinOrigin.parent + parent = when (originParent) { + is KtClassBody -> originParent.parent + else -> originParent + } + } + if (psi is KtAnnotationEntry) { val parentUnwrapped = KotlinConverter.unwrapElements(parent) ?: return null val target = psi.useSiteTarget?.getAnnotationUseSiteTarget() diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt index 640e4f718e0..1b1e67bb4a5 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt @@ -18,7 +18,6 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.* import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.load.java.JvmAbi @@ -27,21 +26,38 @@ import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.* -import org.jetbrains.uast.java.AbstractJavaUClass import org.jetbrains.uast.kotlin.declarations.KotlinUMethod import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier -abstract class AbstractKotlinUClass(private val givenParent: UElement?) : AbstractJavaUClass(), JvmDeclarationUElement { - override val uastParent: UElement? by lz { givenParent ?: convertParent() } +abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClass, JvmDeclarationUElement { + + override val uastDeclarations by lz { + mutableListOf().apply { + addAll(fields) + addAll(initializers) + addAll(methods) + addAll(innerClasses) + } + } + + override val uastSuperTypes: List + get() { + val ktClass = (psi as? KtLightClass)?.kotlinOrigin ?: return emptyList() + return ktClass.superTypeListEntries.mapNotNull { it.typeReference }.map { + LazyKotlinUTypeReferenceExpression(it, this) + } + } + + override val uastAnchor: UElement? + get() = UIdentifier(psi.nameIdentifier, this) + + override val annotations: List by lz { + (sourcePsi as? KtModifierListOwner)?.annotationEntries.orEmpty().map { KotlinUAnnotation(it, this) } + } + + override fun equals(other: Any?) = other is AbstractKotlinUClass && psi == other.psi + override fun hashCode() = psi.hashCode() - //TODO: should be merged with KotlinAbstractUElement.convertParent() after detaching from AbstractJavaUClass - override fun convertParent(): UElement? = - (this.psi as? KtLightClassForLocalDeclaration)?.kotlinOrigin?.parent?.let { - when (it) { - is KtClassBody -> it.parent.toUElement() // TODO: it seems that `class_body`-s are never created in kotlin uast in top-down walk, probably they should be completely skipped and always unwrapped - else -> it.toUElement() - } - } ?: (psi.parent ?: psi.containingFile).toUElement() } open class KotlinUClass private constructor( @@ -63,9 +79,6 @@ open class KotlinUClass private constructor( override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) - override val annotations: List - get() = ktClass?.annotationEntries?.map { KotlinUAnnotation(it, this) } ?: emptyList() - override val uastAnchor: UElement get() = UIdentifier(nameIdentifier, this) @@ -209,8 +222,8 @@ class KotlinUAnonymousClass( class KotlinScriptUClass( psi: KtLightClassForScript, - override val uastParent: UElement? -) : AbstractJavaUClass(), PsiClass by psi { + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), PsiClass by psi { override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, psi.kotlinOrigin) diff --git a/plugins/uast-kotlin/testData/ClassAnnotation.kt b/plugins/uast-kotlin/testData/ClassAnnotation.kt new file mode 100644 index 00000000000..4ae0a54917e --- /dev/null +++ b/plugins/uast-kotlin/testData/ClassAnnotation.kt @@ -0,0 +1,22 @@ +@Test +class A + +annotation class MyAnnotation(val text: String) + +@MyAnnotation("class") +class B { + + @MyAnnotation("inB class") + class InB { + + } + + @MyAnnotation("companion") + companion object { + + } + +} + +@MyAnnotation("object") +object Obj \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/ClassAnnotation.log.txt b/plugins/uast-kotlin/testData/ClassAnnotation.log.txt new file mode 100644 index 00000000000..78f94912a65 --- /dev/null +++ b/plugins/uast-kotlin/testData/ClassAnnotation.log.txt @@ -0,0 +1,30 @@ +UFile (package = ) + UClass (name = A) + UAnnotation (fqName = null) + UAnnotationMethod (name = A) + UClass (name = MyAnnotation) + UAnnotationMethod (name = text) + UClass (name = B) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = text) + ULiteralExpression (value = "class") + UField (name = Companion) + UAnnotation (fqName = null) + UAnnotationMethod (name = B) + UClass (name = InB) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = text) + ULiteralExpression (value = "inB class") + UAnnotationMethod (name = InB) + UClass (name = Companion) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = text) + ULiteralExpression (value = "companion") + UAnnotationMethod (name = Companion) + UClass (name = Obj) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = text) + ULiteralExpression (value = "object") + UField (name = INSTANCE) + UAnnotation (fqName = null) + UAnnotationMethod (name = Obj) diff --git a/plugins/uast-kotlin/testData/ClassAnnotation.render.txt b/plugins/uast-kotlin/testData/ClassAnnotation.render.txt new file mode 100644 index 00000000000..f7a5a5ccced --- /dev/null +++ b/plugins/uast-kotlin/testData/ClassAnnotation.render.txt @@ -0,0 +1,23 @@ +public final class A { + public fun A() = UastEmptyExpression +} + +public abstract annotation MyAnnotation { + public abstract fun text() : java.lang.String = UastEmptyExpression +} + +public final class B { + @null public static final var Companion: B.Companion + public fun B() = UastEmptyExpression + public static final class InB { + public fun InB() = UastEmptyExpression + } + public static final class Companion { + private fun Companion() = UastEmptyExpression + } +} + +public final class Obj { + @null public static final var INSTANCE: Obj + private fun Obj() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin/testData/SimpleScript.render.txt b/plugins/uast-kotlin/testData/SimpleScript.render.txt index 1c119e63966..f3c8859742a 100644 --- a/plugins/uast-kotlin/testData/SimpleScript.render.txt +++ b/plugins/uast-kotlin/testData/SimpleScript.render.txt @@ -1,4 +1,4 @@ -public class SimpleScript : kotlin.script.templates.standard.ScriptTemplateWithArgs { +public class SimpleScript { public final fun getBarOrNull(@org.jetbrains.annotations.NotNull flag: boolean) : SimpleScript.Bar { return if (flag) (42) else null } diff --git a/plugins/uast-kotlin/testData/UnexpectedContainerException.types.txt b/plugins/uast-kotlin/testData/UnexpectedContainerException.types.txt index abfcfc69e45..c12e7197e65 100644 --- a/plugins/uast-kotlin/testData/UnexpectedContainerException.types.txt +++ b/plugins/uast-kotlin/testData/UnexpectedContainerException.types.txt @@ -26,7 +26,7 @@ UFile (package = ) [public abstract interface Callback {...] ULambdaExpression [{ ...}] : PsiType: UBlockExpression [{...}] UObjectLiteralExpression [anonymous object : Callback {... }] : PsiType:Callback - UClass (name = null) [final class null {...}] + UClass (name = null) [final class null : Callback {...}] UAnnotationMethod (name = onError) [public fun onError(@org.jetbrains.annotations.NotNull throwable: java.lang.Throwable) : void {...}] UParameter (name = throwable) [@org.jetbrains.annotations.NotNull var throwable: java.lang.Throwable] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index 86373fe8931..15f6782cca9 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -61,4 +61,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testConstructors() = doTest("Constructors") + + @Test + fun testClassAnnotation() = doTest("ClassAnnotation") }