Uast: returning back secondary constructors bodies (KT-21575)

but secondary constructors without primary constructor will not contain initializers, it is still an issue
This commit is contained in:
Nicolay Mitropolsky
2017-12-01 23:52:43 +03:00
committed by xiexed
parent 962c512882
commit b8069b48c5
9 changed files with 326 additions and 8 deletions
@@ -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<UExpression>().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<KtExpression> {
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<UAnonymousClass, PsiAnonymousClass>(psi)
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUClass>.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)
}
+74
View File
@@ -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
}
}
+149
View File
@@ -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 = <init>)
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 = <init>)
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 = <init>)
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 = <init>)
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 = <init>)
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 = <init>)
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 = <init>)
UBinaryExpression (operator = =)
USimpleNameReferenceExpression (identifier = a)
USimpleNameReferenceExpression (identifier = s)
+76
View File
@@ -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) {
<init>(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) {
<init>(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) {
<init>(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) {
<init>()
a = i.toString()
}
public fun AWithSecondary(s: java.lang.String) {
<init>()
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) {
<init>()
a = i.toString()
}
public fun AWithSecondaryInit(s: java.lang.String) {
<init>()
a = s
}
}
+3 -1
View File
@@ -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)
+3
View File
@@ -95,6 +95,9 @@ UFile (package = )
UIdentifier (Identifier (super))
USimpleNameReferenceExpression (identifier = <init>)
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)
+1
View File
@@ -39,6 +39,7 @@ public final class C : A {
}
public fun C(i: int) {
<init>(i)
println()
}
}
@@ -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)
}
@@ -56,4 +56,7 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
@Test
fun testSuperCalls() = doTest("SuperCalls")
@Test
fun testConstructors() = doTest("Constructors")
}