From b8069b48c514fcc6f623490a21879331263a3e89 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Fri, 1 Dec 2017 23:52:43 +0300 Subject: [PATCH] Uast: returning back secondary constructors bodies (KT-21575) but secondary constructors without primary constructor will not contain initializers, it is still an issue --- .../uast/kotlin/declarations/KotlinUClass.kt | 22 ++- plugins/uast-kotlin/testData/Constructors.kt | 74 +++++++++ .../uast-kotlin/testData/Constructors.log.txt | 149 ++++++++++++++++++ .../testData/Constructors.render.txt | 76 +++++++++ plugins/uast-kotlin/testData/SuperCalls.kt | 4 +- .../uast-kotlin/testData/SuperCalls.log.txt | 3 + .../testData/SuperCalls.render.txt | 1 + .../tests/AbstractKotlinRenderLogTest.kt | 2 +- .../tests/SimpleKotlinRenderLogTest.kt | 3 + 9 files changed, 326 insertions(+), 8 deletions(-) create mode 100644 plugins/uast-kotlin/testData/Constructors.kt create mode 100644 plugins/uast-kotlin/testData/Constructors.log.txt create mode 100644 plugins/uast-kotlin/testData/Constructors.render.txt 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 3df256ff1b9..d671fe73ae9 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 @@ -128,27 +128,37 @@ class KotlinConstructorUMethod( else -> null } } - val initializers = ktClass?.getAnonymousInitializers().orEmpty() - if (delegationCall == null && initializers.isEmpty()) return@lz null + val bodyExpressions = getBodyExpressions() + if (delegationCall == null && bodyExpressions.isEmpty()) return@lz null KotlinUBlockExpression.KotlinLazyUBlockExpression(this) { uastParent -> SmartList().apply { delegationCall?.let { add(KotlinUFunctionCallExpression(it, uastParent)) } val languagePlugin = uastParent.getLanguagePlugin() - initializers.forEach { - addIfNotNull(languagePlugin.convertOpt(it.body, uastParent)) + bodyExpressions.forEach { + addIfNotNull(languagePlugin.convertOpt(it, uastParent)) } } } } + + private fun getBodyExpressions(): List { + if (isPrimary) return getInitializers() + val bodyExpression = (psi.kotlinOrigin as? KtFunction)?.bodyExpression ?: return emptyList() + if (bodyExpression is KtBlockExpression) return bodyExpression.statements + return listOf(bodyExpression) + } + + private fun getInitializers() = ktClass?.getAnonymousInitializers()?.mapNotNull { it.body } ?: emptyList() + } class KotlinUAnonymousClass( psi: PsiAnonymousClass, givenParent: UElement? ) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi { - + override val psi: PsiAnonymousClass = unwrap(psi) override fun getOriginalElement(): PsiElement? = super.getOriginalElement() @@ -163,7 +173,7 @@ class KotlinUAnonymousClass( override val uastAnchor: UElement? get() { - val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return null + val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return null return UIdentifier(ktClassOrObject.getObjectKeyword(), this) } diff --git a/plugins/uast-kotlin/testData/Constructors.kt b/plugins/uast-kotlin/testData/Constructors.kt new file mode 100644 index 00000000000..dccd7e134bd --- /dev/null +++ b/plugins/uast-kotlin/testData/Constructors.kt @@ -0,0 +1,74 @@ +class A(val str: String) { + + constructor(i: Int) : this(i.toString()) + +} + +class AWithInit(val str: String) { + + init { + println() + } + + constructor(i: Int) : this(i.toString()) + +} + +class AWith2Init(val str: String) { + + init { + println(1) + } + + init { + println(2) + } + + constructor(i: Int) : this(i.toString()) + +} + +class AOnlyInit { + + init { + println(1) + } + + init { + println(2) + } +} + +class AWithSecondary { + + lateinit var a: String + + constructor(i: Int) { + a = i.toString() + } + + constructor(s: String) { + a = s + } + +} + +class AWithSecondaryInit { + + lateinit var a: String + + init { + // This body will not be picked by UAST because no lightMethod contains it. + // Of course it is not a desired behaviour, so fix it if you know how + println() + } + + constructor(i: Int) { + a = i.toString() + } + + constructor(s: String) { + a = s + } + +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/Constructors.log.txt b/plugins/uast-kotlin/testData/Constructors.log.txt new file mode 100644 index 00000000000..7a162e6ac93 --- /dev/null +++ b/plugins/uast-kotlin/testData/Constructors.log.txt @@ -0,0 +1,149 @@ +UFile (package = ) + UClass (name = A) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getStr) + UAnnotationMethod (name = A) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = A) + UParameter (name = i) + UAnnotation (fqName = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = ) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) + UClass (name = AWithInit) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getStr) + UAnnotationMethod (name = AWithInit) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) + UAnnotationMethod (name = AWithInit) + UParameter (name = i) + UAnnotation (fqName = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = ) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) + UClass (name = AWith2Init) + UField (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getStr) + UAnnotationMethod (name = AWith2Init) + UParameter (name = str) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) + ULiteralExpression (value = 1) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) + ULiteralExpression (value = 2) + UAnnotationMethod (name = AWith2Init) + UParameter (name = i) + UAnnotation (fqName = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + UIdentifier (Identifier (this)) + USimpleNameReferenceExpression (identifier = ) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) + UClass (name = AOnlyInit) + UAnnotationMethod (name = AOnlyInit) + UBlockExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) + ULiteralExpression (value = 1) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) + ULiteralExpression (value = 2) + UClass (name = AWithSecondary) + UField (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getA) + UAnnotationMethod (name = setA) + UParameter (name = p) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = AWithSecondary) + UParameter (name = i) + UAnnotation (fqName = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = ) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) + UAnnotationMethod (name = AWithSecondary) + UParameter (name = s) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = ) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + USimpleNameReferenceExpression (identifier = s) + UClass (name = AWithSecondaryInit) + UField (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = getA) + UAnnotationMethod (name = setA) + UParameter (name = p) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotationMethod (name = AWithSecondaryInit) + UParameter (name = i) + UAnnotation (fqName = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = ) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (toString)) + USimpleNameReferenceExpression (identifier = toString) + UAnnotationMethod (name = AWithSecondaryInit) + UParameter (name = s) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier ()) + USimpleNameReferenceExpression (identifier = ) + UBinaryExpression (operator = =) + USimpleNameReferenceExpression (identifier = a) + USimpleNameReferenceExpression (identifier = s) diff --git a/plugins/uast-kotlin/testData/Constructors.render.txt b/plugins/uast-kotlin/testData/Constructors.render.txt new file mode 100644 index 00000000000..8a3db9fa922 --- /dev/null +++ b/plugins/uast-kotlin/testData/Constructors.render.txt @@ -0,0 +1,76 @@ +public final class A { + private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun A(str: java.lang.String) = UastEmptyExpression + public fun A(i: int) { + (i.toString()) + } +} + +public final class AWithInit { + private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun AWithInit(str: java.lang.String) { + { + println() + } + } + public fun AWithInit(i: int) { + (i.toString()) + } +} + +public final class AWith2Init { + private final var str: java.lang.String + public final fun getStr() : java.lang.String = UastEmptyExpression + public fun AWith2Init(str: java.lang.String) { + { + println(1) + } + { + println(2) + } + } + public fun AWith2Init(i: int) { + (i.toString()) + } +} + +public final class AOnlyInit { + public fun AOnlyInit() { + { + println(1) + } + { + println(2) + } + } +} + +public final class AWithSecondary { + public var a: java.lang.String + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(p: java.lang.String) : void = UastEmptyExpression + public fun AWithSecondary(i: int) { + () + a = i.toString() + } + public fun AWithSecondary(s: java.lang.String) { + () + a = s + } +} + +public final class AWithSecondaryInit { + public var a: java.lang.String + public final fun getA() : java.lang.String = UastEmptyExpression + public final fun setA(p: java.lang.String) : void = UastEmptyExpression + public fun AWithSecondaryInit(i: int) { + () + a = i.toString() + } + public fun AWithSecondaryInit(s: java.lang.String) { + () + a = s + } +} diff --git a/plugins/uast-kotlin/testData/SuperCalls.kt b/plugins/uast-kotlin/testData/SuperCalls.kt index c1da1b30fab..7ec534caf35 100644 --- a/plugins/uast-kotlin/testData/SuperCalls.kt +++ b/plugins/uast-kotlin/testData/SuperCalls.kt @@ -11,7 +11,9 @@ class B(param: String) : A(param) class C : A { constructor(p: String) : super(p) - constructor(i: Int) : super(i) + constructor(i: Int) : super(i) { + println() + } override fun foo(a: Long) { super.foo(a) diff --git a/plugins/uast-kotlin/testData/SuperCalls.log.txt b/plugins/uast-kotlin/testData/SuperCalls.log.txt index 897e43fe962..72f6c3fd797 100644 --- a/plugins/uast-kotlin/testData/SuperCalls.log.txt +++ b/plugins/uast-kotlin/testData/SuperCalls.log.txt @@ -95,6 +95,9 @@ UFile (package = ) UIdentifier (Identifier (super)) USimpleNameReferenceExpression (identifier = ) USimpleNameReferenceExpression (identifier = i) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (println)) + USimpleNameReferenceExpression (identifier = println) UClass (name = O) UField (name = INSTANCE) UAnnotation (fqName = null) diff --git a/plugins/uast-kotlin/testData/SuperCalls.render.txt b/plugins/uast-kotlin/testData/SuperCalls.render.txt index 12545427485..57d7af7d086 100644 --- a/plugins/uast-kotlin/testData/SuperCalls.render.txt +++ b/plugins/uast-kotlin/testData/SuperCalls.render.txt @@ -39,6 +39,7 @@ public final class C : A { } public fun C(i: int) { (i) + println() } } diff --git a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt index b1609330718..337179fbcfc 100644 --- a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt @@ -72,7 +72,7 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog if (expectedParents != null) { assertNotNull("Expected to be able to convert PSI element $element", uElement) val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() } - assertEquals("Inconsistent parents for ${uElement.asLogString()} (converted from $element)", expectedParents, parents) + assertEquals("Inconsistent parents for ${uElement.asRenderString()}(${uElement.asLogString()})(${uElement.javaClass}) (converted from $element[${element.text}])", expectedParents, parents) } super.visitElement(element) } diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index 3260e0aad58..d86400a434a 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -56,4 +56,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testSuperCalls() = doTest("SuperCalls") + + @Test + fun testConstructors() = doTest("Constructors") }