From 9c674cb7c32487428e0206b04d62a02c23f5399b Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Mon, 25 Feb 2019 15:43:02 +0300 Subject: [PATCH] Uast: support for `KtDelegatedSuperTypeEntry` (KT-30033) --- .../uast/kotlin/KotlinUastLanguagePlugin.kt | 6 ++ .../kotlin/KotlinUastLanguagePlugin.kt.182 | 6 ++ .../kotlin/KotlinUastLanguagePlugin.kt.191 | 6 ++ .../uast/kotlin/declarations/KotlinUClass.kt | 49 +++++++++++++--- .../uast/kotlin/declarations/KotlinUFile.kt | 4 +- .../kinds/KotlinSpecialExpressionKinds.kt | 3 + .../testData/ConstructorDelegate.kt | 15 +++++ .../testData/ConstructorDelegate.log.txt | 48 ++++++++++++++++ .../testData/ConstructorDelegate.render.txt | 25 ++++++++ plugins/uast-kotlin/testData/Delegate.log.txt | 57 +++++++++++++++++++ .../uast-kotlin/testData/Delegate.render.txt | 21 +++++++ .../tests/SimpleKotlinRenderLogTest.kt | 6 ++ .../tests/SimpleKotlinRenderLogTest.kt.191 | 6 ++ 13 files changed, 242 insertions(+), 10 deletions(-) create mode 100644 plugins/uast-kotlin/testData/ConstructorDelegate.kt create mode 100644 plugins/uast-kotlin/testData/ConstructorDelegate.log.txt create mode 100644 plugins/uast-kotlin/testData/ConstructorDelegate.render.txt create mode 100644 plugins/uast-kotlin/testData/Delegate.log.txt create mode 100644 plugins/uast-kotlin/testData/Delegate.render.txt diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index fe546308a93..9b9a2daaf54 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -157,6 +157,7 @@ internal object KotlinConverter { is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent) is KtLightParameterList -> unwrapElements(element.parent) is KtTypeElement -> unwrapElements(element.parent) + is KtSuperTypeList -> unwrapElements(element.parent) else -> element } @@ -489,6 +490,9 @@ internal object KotlinConverter { el { KotlinUNestedAnnotation.tryCreate(original, givenParent) } } else null is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, requiredType) + is KtDelegatedSuperTypeEntry -> el { + KotlinSupertypeDelegationUExpression(original, givenParent) + } else -> null } } @@ -565,3 +569,5 @@ private fun convertVariablesDeclaration( } return declarationsExpression.apply { declarations = listOf(variable) } } + +val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin() diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.182 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.182 index fb0b25600da..543409060e6 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.182 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.182 @@ -155,6 +155,7 @@ internal object KotlinConverter { is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent) is KtLightParameterList -> unwrapElements(element.parent) is KtTypeElement -> unwrapElements(element.parent) + is KtSuperTypeList -> unwrapElements(element.parent) else -> element } @@ -487,6 +488,9 @@ internal object KotlinConverter { el { KotlinUNestedAnnotation.tryCreate(original, givenParent) } } else null is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, requiredType) + is KtDelegatedSuperTypeEntry -> el { + KotlinSupertypeDelegationUExpression(original, givenParent) + } else -> null } } @@ -563,3 +567,5 @@ private fun convertVariablesDeclaration( } return declarationsExpression.apply { declarations = listOf(variable) } } + +val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin() diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.191 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.191 index c53afda6f70..33a852a37f9 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.191 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.191 @@ -187,6 +187,7 @@ internal object KotlinConverter { is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent) is KtLightParameterList -> unwrapElements(element.parent) is KtTypeElement -> unwrapElements(element.parent) + is KtSuperTypeList -> unwrapElements(element.parent) else -> element } @@ -515,6 +516,9 @@ internal object KotlinConverter { el { KotlinUNestedAnnotation.tryCreate(original, givenParent) } } else null is KtLightAnnotationForSourceEntry -> convertDeclarationOrElement(original.kotlinOrigin, givenParent, expectedTypes) + is KtDelegatedSuperTypeEntry -> el { + KotlinSupertypeDelegationUExpression(original, givenParent) + } else -> null } } @@ -640,6 +644,8 @@ private fun convertVariablesDeclaration( return declarationsExpression.apply { declarations = listOf(variable) } } +val kotlinUastPlugin get() = UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin() + private fun expressionTypes(requiredType: Class?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST private fun elementTypes(requiredType: Class?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST 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 6716217b4c0..dbc87864f51 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 @@ -27,9 +27,12 @@ import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier import org.jetbrains.uast.kotlin.declarations.KotlinUMethod import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier +import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds +import org.jetbrains.uast.visitor.UastVisitor abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClassTypeSpecific, UAnchorOwner, JvmDeclarationUElementPlaceholder { @@ -43,14 +46,26 @@ abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUEle } } + open val ktClass: KtClassOrObject? get() = (psi as? KtLightClass)?.kotlinOrigin + override val uastSuperTypes: List - get() { - val ktClass = (psi as? KtLightClass)?.kotlinOrigin ?: return emptyList() - return ktClass.superTypeListEntries.mapNotNull { it.typeReference }.map { - LazyKotlinUTypeReferenceExpression(it, this) - } + get() = ktClass?.superTypeListEntries.orEmpty().mapNotNull { it.typeReference }.map { + LazyKotlinUTypeReferenceExpression(it, this) } + val delegateExpressions: List + get() = ktClass?.superTypeListEntries.orEmpty() + .filterIsInstance() + .map { KotlinSupertypeDelegationUExpression(it, this) } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitClass(this)) return + delegateExpressions.acceptList(visitor) + annotations.acceptList(visitor) + uastDeclarations.acceptList(visitor) + visitor.afterVisitClass(this) + } + override val annotations: List by lz { (sourcePsi as? KtModifierListOwner)?.annotationEntries.orEmpty().map { KotlinUAnnotation(it, this) } } @@ -60,12 +75,32 @@ abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUEle } +class KotlinSupertypeDelegationUExpression(override val sourcePsi: KtDelegatedSuperTypeEntry, givenParent: UElement?) : + KotlinAbstractUExpression(givenParent), UExpressionList { + + override val psi: PsiElement? get() = sourcePsi + + val typeReference: UTypeReferenceExpression? by lazy { + sourcePsi.typeReference?.let { KotlinUTypeReferenceExpression(it.toPsiType(this), it, this) } + } + + val delegateExpression: UExpression? by lazy { + sourcePsi.delegateExpression?.let { kotlinUastPlugin.convertElement(it, this, UExpression::class.java) as? UExpression } + } + + override val expressions: List + get() = listOfNotNull(typeReference, delegateExpression) + + override val kind: UastSpecialExpressionKind get() = KotlinSpecialExpressionKinds.SUPER_DELEGATION + +} + open class KotlinUClass private constructor( psi: KtLightClass, givenParent: UElement? ) : AbstractKotlinUClass(givenParent), PsiClass by psi { - val ktClass = psi.kotlinOrigin + final override val ktClass = psi.kotlinOrigin override val javaPsi: KtLightClass = psi @@ -214,7 +249,7 @@ class KotlinUAnonymousClass( override val javaPsi: PsiAnonymousClass = psi - override val sourcePsi: KtClassOrObject? = (psi as? KtLightClass)?.kotlinOrigin + override val sourcePsi: KtClassOrObject? = ktClass override fun getOriginalElement(): PsiElement? = super.getOriginalElement() diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt index 84e33f39e78..690861f455a 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt @@ -22,7 +22,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiRecursiveElementWalkingVisitor import org.jetbrains.kotlin.asJava.findFacadeClass import org.jetbrains.kotlin.asJava.toLightClass -import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.uast.* @@ -30,8 +29,7 @@ import java.util.* class KotlinUFile( override val psi: KtFile, - override val languagePlugin: UastLanguagePlugin = - UastLanguagePlugin.getInstances().find { it.language == KotlinLanguage.INSTANCE } ?: KotlinUastLanguagePlugin() + override val languagePlugin: UastLanguagePlugin = kotlinUastPlugin ) : UFile, JvmDeclarationUElementPlaceholder { override val packageName: String get() = psi.packageFqName.asString() diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/kinds/KotlinSpecialExpressionKinds.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/kinds/KotlinSpecialExpressionKinds.kt index 00d1b05cb42..0c93ad2d26d 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/kinds/KotlinSpecialExpressionKinds.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/kinds/KotlinSpecialExpressionKinds.kt @@ -30,4 +30,7 @@ object KotlinSpecialExpressionKinds { @JvmField val ELVIS = UastSpecialExpressionKind("elvis") + + @JvmField + val SUPER_DELEGATION = UastSpecialExpressionKind("super_delegation") } \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/ConstructorDelegate.kt b/plugins/uast-kotlin/testData/ConstructorDelegate.kt new file mode 100644 index 00000000000..3da6ec1a8c2 --- /dev/null +++ b/plugins/uast-kotlin/testData/ConstructorDelegate.kt @@ -0,0 +1,15 @@ +interface Base { + fun print() +} + +class BaseImpl(val x: Int) : Base { + override fun print() { + print(x) + } +} + +class Derived(b: Base) : Base by createBase(10), CharSequence by "abc" + +fun createBase(i: Int): Base { + return BaseImpl(i) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/ConstructorDelegate.log.txt b/plugins/uast-kotlin/testData/ConstructorDelegate.log.txt new file mode 100644 index 00000000000..4f9eccfebf3 --- /dev/null +++ b/plugins/uast-kotlin/testData/ConstructorDelegate.log.txt @@ -0,0 +1,48 @@ +UFile (package = ) + UClass (name = ConstructorDelegateKt) + UAnnotationMethod (name = createBase) + UParameter (name = i) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (BaseImpl)) + USimpleNameReferenceExpression (identifier = , resolvesTo = BaseImpl) + USimpleNameReferenceExpression (identifier = i) + UClass (name = Base) + UAnnotationMethod (name = print) + UClass (name = BaseImpl) + UField (name = x) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = print) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (print)) + USimpleNameReferenceExpression (identifier = print, resolvesTo = null) + USimpleNameReferenceExpression (identifier = x) + UAnnotationMethod (name = getX) + UAnnotationMethod (name = BaseImpl) + UParameter (name = x) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UClass (name = Derived) + UExpressionList (super_delegation) + UTypeReferenceExpression (name = Base) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (createBase)) + USimpleNameReferenceExpression (identifier = createBase, resolvesTo = null) + ULiteralExpression (value = 10) + UExpressionList (super_delegation) + UTypeReferenceExpression (name = java.lang.CharSequence) + ULiteralExpression (value = "abc") + UAnnotationMethod (name = Derived) + UParameter (name = b) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getLength) + UAnnotationMethod (name = get) + UParameter (name = index) + UAnnotation (fqName = null) + UAnnotationMethod (name = subSequence) + UParameter (name = startIndex) + UAnnotation (fqName = null) + UParameter (name = endIndex) + UAnnotation (fqName = null) diff --git a/plugins/uast-kotlin/testData/ConstructorDelegate.render.txt b/plugins/uast-kotlin/testData/ConstructorDelegate.render.txt new file mode 100644 index 00000000000..4609aaaf924 --- /dev/null +++ b/plugins/uast-kotlin/testData/ConstructorDelegate.render.txt @@ -0,0 +1,25 @@ +public final class ConstructorDelegateKt { + public static final fun createBase(@org.jetbrains.annotations.NotNull i: int) : Base { + return (i) + } +} + +public abstract interface Base { + public abstract fun print() : void = UastEmptyExpression +} + +public final class BaseImpl : Base { + @org.jetbrains.annotations.NotNull private final var x: int + public fun print() : void { + print(x) + } + public final fun getX() : int = UastEmptyExpression + public fun BaseImpl(@org.jetbrains.annotations.NotNull x: int) = UastEmptyExpression +} + +public final class Derived : Base, java.lang.CharSequence { + public fun Derived(@org.jetbrains.annotations.NotNull b: Base) = UastEmptyExpression + public fun getLength() : int = UastEmptyExpression + public fun get(@null index: int) : char = UastEmptyExpression + public fun subSequence(@null startIndex: int, @null endIndex: int) : java.lang.CharSequence = UastEmptyExpression +} diff --git a/plugins/uast-kotlin/testData/Delegate.log.txt b/plugins/uast-kotlin/testData/Delegate.log.txt new file mode 100644 index 00000000000..212c16989e1 --- /dev/null +++ b/plugins/uast-kotlin/testData/Delegate.log.txt @@ -0,0 +1,57 @@ +UFile (package = ) + UClass (name = MyColor) + UField (name = x) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UField (name = y) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UField (name = z) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getX) + UAnnotationMethod (name = getY) + UAnnotationMethod (name = getZ) + UAnnotationMethod (name = MyColor) + UParameter (name = x) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = y) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = z) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UClass (name = Some) + UField (name = delegate$delegate) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (lazy)) + USimpleNameReferenceExpression (identifier = lazy, resolvesTo = null) + ULambdaExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 3)) + UIdentifier (Identifier (MyColor)) + USimpleNameReferenceExpression (identifier = , resolvesTo = MyColor) + ULiteralExpression (value = 18) + ULiteralExpression (value = 2) + ULiteralExpression (value = 3) + UField (name = lambda) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (lazy)) + USimpleNameReferenceExpression (identifier = lazy, resolvesTo = null) + ULambdaExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 3)) + UIdentifier (Identifier (MyColor)) + USimpleNameReferenceExpression (identifier = , resolvesTo = MyColor) + ULiteralExpression (value = 1) + ULiteralExpression (value = 2) + ULiteralExpression (value = 3) + UField (name = nonLazy) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 3)) + UIdentifier (Identifier (MyColor)) + USimpleNameReferenceExpression (identifier = , resolvesTo = MyColor) + ULiteralExpression (value = 1) + ULiteralExpression (value = 2) + ULiteralExpression (value = 3) + UAnnotationMethod (name = getDelegate) + UAnnotationMethod (name = getLambda) + UAnnotationMethod (name = getNonLazy) + UAnnotationMethod (name = Some) diff --git a/plugins/uast-kotlin/testData/Delegate.render.txt b/plugins/uast-kotlin/testData/Delegate.render.txt new file mode 100644 index 00000000000..4200b574aab --- /dev/null +++ b/plugins/uast-kotlin/testData/Delegate.render.txt @@ -0,0 +1,21 @@ +public final class MyColor { + @org.jetbrains.annotations.NotNull private final var x: int + @org.jetbrains.annotations.NotNull private final var y: int + @org.jetbrains.annotations.NotNull private final var z: int + public final fun getX() : int = UastEmptyExpression + public final fun getY() : int = UastEmptyExpression + public final fun getZ() : int = UastEmptyExpression + public fun MyColor(@org.jetbrains.annotations.NotNull x: int, @org.jetbrains.annotations.NotNull y: int, @org.jetbrains.annotations.NotNull z: int) = UastEmptyExpression +} + +public final class Some { + @org.jetbrains.annotations.NotNull private final var delegate$delegate: kotlin.Lazy + @org.jetbrains.annotations.NotNull private final var lambda: kotlin.Lazy = lazy({ + (1, 2, 3) + }) + @org.jetbrains.annotations.NotNull private final var nonLazy: MyColor = (1, 2, 3) + public final fun getDelegate() : MyColor = UastEmptyExpression + public final fun getLambda() : kotlin.Lazy = UastEmptyExpression + public final fun getNonLazy() : MyColor = UastEmptyExpression + public fun Some() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index a3b4e418715..842dd418601 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -84,4 +84,10 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testLambdas() = doTest("Lambdas") + + @Test + fun testDelegate() = doTest("Delegate") + + @Test + fun testConstructorDelegate() = doTest("ConstructorDelegate") } diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.191 b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.191 index d33aa51ac19..8d464f36a72 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.191 +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.191 @@ -90,6 +90,12 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testLambdas() = doTest("Lambdas") + + @Test + fun testDelegate() = doTest("Delegate") + + @Test + fun testConstructorDelegate() = doTest("ConstructorDelegate") } fun withForceUInjectionHostValue(call: () -> Unit) {