From a180d78eaf1145bf5b760adeb32f572d6d829135 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Wed, 3 Jul 2019 12:01:51 +0300 Subject: [PATCH] Uast: implicit returns for local function bodies (KT-32370) --- .../uast/kotlin/KotlinAbstractUElement.kt | 3 +- .../uast/kotlin/KotlinAbstractUElement.kt.183 | 3 +- .../uast/kotlin/declarations/KotlinUMethod.kt | 28 ++++++++++--------- .../kotlin/declarations/KotlinUMethod.kt.183 | 28 ++++++++++--------- .../kotlin/declarations/KotlinUMethod.kt.192 | 28 ++++++++++--------- .../uast/kotlin/expressions/LocalFunction.kt | 7 +++-- plugins/uast-kotlin/testData/LambdaReturn.kt | 1 + .../uast-kotlin/testData/LambdaReturn.log.txt | 10 +++++++ .../testData/LambdaReturn.render.txt | 3 ++ .../testData/LocalDeclarations.log.txt | 12 +++++--- .../testData/LocalDeclarations.render.txt | 4 +-- .../testData/LocalDeclarations.types.txt | 12 +++++--- .../testData/LocalDeclarations.values.txt | 12 +++++--- 13 files changed, 94 insertions(+), 57 deletions(-) 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 45e0f671a39..295d0b2dc61 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.expressions.KotlinLocalFunctionULambdaExpression import org.jetbrains.uast.kotlin.expressions.KotlinUElvisExpression import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable @@ -188,7 +189,7 @@ fun doConvertParent(element: UElement, parent: PsiElement?): UElement? { } } - if (result is UMethod + if ((result is UMethod || result is KotlinLocalFunctionULambdaExpression) && result !is KotlinConstructorUMethod // no sense to wrap super calls with `return` && element is UExpression && element !is UBlockExpression diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 index a1f5d4a703c..3fb23d1fa99 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt.183 @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.expressions.KotlinLocalFunctionULambdaExpression import org.jetbrains.uast.kotlin.expressions.KotlinUElvisExpression import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable @@ -184,7 +185,7 @@ fun doConvertParent(element: UElement, parent: PsiElement?): UElement? { } } - if (result is UMethod + if ((result is UMethod || result is KotlinLocalFunctionULambdaExpression) && result !is KotlinConstructorUMethod // no sense to wrap super calls with `return` && element is UExpression && element !is UBlockExpression diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt index 6795ae95096..764a2ceb594 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt @@ -102,18 +102,7 @@ open class KotlinUMethod( else -> null } ?: return@lz null - when (bodyExpression) { - !is KtBlockExpression -> { - KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block -> - val implicitReturn = KotlinUImplicitReturnExpression(block) - val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression - ?: return@KotlinLazyUBlockExpression emptyList() - listOf(implicitReturn.apply { returnExpression = uBody }) - }) - - } - else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression - } + wrapExpressionBody(this, bodyExpression) } override val isOverride: Boolean @@ -142,4 +131,17 @@ open class KotlinUMethod( else KotlinUMethod(psi, containingElement) } -} \ No newline at end of file +} + +internal fun wrapExpressionBody(function: UElement, bodyExpression: KtExpression): UExpression? = when (bodyExpression) { + !is KtBlockExpression -> { + KotlinUBlockExpression.KotlinLazyUBlockExpression(function) { block -> + val implicitReturn = KotlinUImplicitReturnExpression(block) + val uBody = function.getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression + ?: return@KotlinLazyUBlockExpression emptyList() + listOf(implicitReturn.apply { returnExpression = uBody }) + } + + } + else -> function.getLanguagePlugin().convertElement(bodyExpression, function) as? UExpression +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 index fb4487692ce..6230aabae73 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.183 @@ -102,18 +102,7 @@ open class KotlinUMethod( else -> null } ?: return@lz null - when (bodyExpression) { - !is KtBlockExpression -> { - KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block -> - val implicitReturn = KotlinUImplicitReturnExpression(block) - val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression - ?: return@KotlinLazyUBlockExpression emptyList() - listOf(implicitReturn.apply { returnExpression = uBody }) - }) - - } - else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression - } + wrapExpressionBody(this, bodyExpression) } override val isOverride: Boolean @@ -136,4 +125,17 @@ open class KotlinUMethod( else KotlinUMethod(psi, containingElement) } -} \ No newline at end of file +} + +internal fun wrapExpressionBody(function: UElement, bodyExpression: KtExpression): UExpression? = when (bodyExpression) { + !is KtBlockExpression -> { + KotlinUBlockExpression.KotlinLazyUBlockExpression(function) { block -> + val implicitReturn = KotlinUImplicitReturnExpression(block) + val uBody = function.getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression + ?: return@KotlinLazyUBlockExpression emptyList() + listOf(implicitReturn.apply { returnExpression = uBody }) + } + + } + else -> function.getLanguagePlugin().convertElement(bodyExpression, function) as? UExpression +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.192 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.192 index dadf7d6789b..543e2041ad2 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.192 +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.192 @@ -102,18 +102,7 @@ open class KotlinUMethod( else -> null } ?: return@lz null - when (bodyExpression) { - !is KtBlockExpression -> { - KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block -> - val implicitReturn = KotlinUImplicitReturnExpression(block) - val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression - ?: return@KotlinLazyUBlockExpression emptyList() - listOf(implicitReturn.apply { returnExpression = uBody }) - }) - - } - else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression - } + wrapExpressionBody(this, bodyExpression) } override fun getBody(): PsiCodeBlock? = super.getBody() @@ -139,4 +128,17 @@ open class KotlinUMethod( else KotlinUMethod(psi, containingElement) } -} \ No newline at end of file +} + +internal fun wrapExpressionBody(function: UElement, bodyExpression: KtExpression): UExpression? = when (bodyExpression) { + !is KtBlockExpression -> { + KotlinUBlockExpression.KotlinLazyUBlockExpression(function) { block -> + val implicitReturn = KotlinUImplicitReturnExpression(block) + val uBody = function.getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression + ?: return@KotlinLazyUBlockExpression emptyList() + listOf(implicitReturn.apply { returnExpression = uBody }) + } + + } + else -> function.getLanguagePlugin().convertElement(bodyExpression, function) as? UExpression +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/LocalFunction.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/LocalFunction.kt index 58913e38b53..1f393ee7c8e 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/LocalFunction.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/LocalFunction.kt @@ -7,6 +7,7 @@ import com.intellij.psi.PsiVariable import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.uast.* import org.jetbrains.uast.kotlin.* +import org.jetbrains.uast.kotlin.declarations.wrapExpressionBody import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable @@ -36,13 +37,15 @@ internal class KotlinLocalFunctionUVariable( } -private class KotlinLocalFunctionULambdaExpression( +internal class KotlinLocalFunctionULambdaExpression( override val sourcePsi: KtFunction, givenParent: UElement? ): KotlinAbstractUExpression(givenParent), ULambdaExpression { override val functionalInterfaceType: PsiType? = null - override val body by lz { KotlinConverter.convertOrEmpty(sourcePsi.bodyExpression, this) } + override val body by lz { + sourcePsi.bodyExpression?.let { wrapExpressionBody(this, it) } ?: UastEmptyExpression(this) + } override val valueParameters by lz { sourcePsi.valueParameters.mapIndexed { i, p -> diff --git a/plugins/uast-kotlin/testData/LambdaReturn.kt b/plugins/uast-kotlin/testData/LambdaReturn.kt index 6b2d9caa926..c8ac6df4115 100644 --- a/plugins/uast-kotlin/testData/LambdaReturn.kt +++ b/plugins/uast-kotlin/testData/LambdaReturn.kt @@ -29,6 +29,7 @@ fun foo() { return "2" } + val lam5 = fun(a: Int) = "a" + a bar { if (it > 5) return diff --git a/plugins/uast-kotlin/testData/LambdaReturn.log.txt b/plugins/uast-kotlin/testData/LambdaReturn.log.txt index 78d672dc311..ebcadc19e70 100644 --- a/plugins/uast-kotlin/testData/LambdaReturn.log.txt +++ b/plugins/uast-kotlin/testData/LambdaReturn.log.txt @@ -69,6 +69,16 @@ UFile (package = org.jetbrains.uast.kotlin) ULiteralExpression (value = "1") UReturnExpression ULiteralExpression (value = "2") + UDeclarationsExpression + ULocalVariable (name = lam5) + ULambdaExpression + UParameter (name = a) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UReturnExpression + UBinaryExpression (operator = +) + ULiteralExpression (value = "a") + USimpleNameReferenceExpression (identifier = a) UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) UIdentifier (Identifier (bar)) USimpleNameReferenceExpression (identifier = bar, resolvesTo = null) diff --git a/plugins/uast-kotlin/testData/LambdaReturn.render.txt b/plugins/uast-kotlin/testData/LambdaReturn.render.txt index 7bd2eb75ab9..fc96cb4cd9c 100644 --- a/plugins/uast-kotlin/testData/LambdaReturn.render.txt +++ b/plugins/uast-kotlin/testData/LambdaReturn.render.txt @@ -21,6 +21,9 @@ public final class LambdaReturnKt { if (a < 5) return "5" if (a > 0) return "1" else return "2" } + var lam5: kotlin.jvm.functions.Function1 = fun (@org.jetbrains.annotations.NotNull var a: int) { + return "a" + a + } bar({ if (it > 5) return var b: int = 1 diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt index 1b116f7c895..013b37226b2 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt @@ -8,9 +8,11 @@ UFile (package = ) UDeclarationsExpression UVariable (name = bar) ULambdaExpression - UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) - UIdentifier (Identifier (Local)) - USimpleNameReferenceExpression (identifier = , resolvesTo = Local) + UBlockExpression + UReturnExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier (Local)) + USimpleNameReferenceExpression (identifier = , resolvesTo = Local) UDeclarationsExpression ULocalVariable (name = baz) ULambdaExpression @@ -23,7 +25,9 @@ UFile (package = ) ULambdaExpression UParameter (name = text) UAnnotation (fqName = org.jetbrains.annotations.NotNull) - ULiteralExpression (value = 42) + UBlockExpression + UReturnExpression + ULiteralExpression (value = 42) UDeclarationsExpression UClass (name = LocalObject) UField (name = INSTANCE) diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt index b4a41c7ddb2..0805df0ce43 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt @@ -4,13 +4,13 @@ public final class LocalDeclarationsKt { public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression } var bar: = fun () { - () + return () } var baz: kotlin.jvm.functions.Function0 = fun () { () } var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) { - 42 + return 42 } public static final class LocalObject { @null public static final var INSTANCE: LocalDeclarationsKt.foo.LocalObject diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt index e067345b74d..a26bc6f2238 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt @@ -8,9 +8,11 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UDeclarationsExpression [var bar: = fun () {...}] UVariable (name = bar) [var bar: = fun () {...}] ULambdaExpression [fun () {...}] - UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: - UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] - USimpleNameReferenceExpression (identifier = , resolvesTo = Local) [] : PsiType: + UBlockExpression [{...}] + UReturnExpression [return ()] + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = , resolvesTo = Local) [] : PsiType: UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0 = fun () {...}] ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0 = fun () {...}] ULambdaExpression [fun () {...}] @@ -23,7 +25,9 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] - ULiteralExpression (value = 42) [42] : PsiType:int + UBlockExpression [{...}] + UReturnExpression [return 42] + ULiteralExpression (value = 42) [42] : PsiType:int UDeclarationsExpression [public static final class LocalObject {...}] UClass (name = LocalObject) [public static final class LocalObject {...}] UField (name = INSTANCE) [@null public static final var INSTANCE: LocalDeclarationsKt.foo.LocalObject] diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt index 12391ba6052..4cb4472a3cf 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt @@ -8,9 +8,11 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UDeclarationsExpression [var bar: = fun () {...}] = Undetermined UVariable (name = bar) [var bar: = fun () {...}] ULambdaExpression [fun () {...}] = Undetermined - UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() - UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] - USimpleNameReferenceExpression (identifier = , resolvesTo = Local) [] = external ()() + UBlockExpression [{...}] = Nothing + UReturnExpression [return ()] = Undetermined + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = , resolvesTo = Local) [] = external ()() UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0 = fun () {...}] = Undetermined ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0 = fun () {...}] ULambdaExpression [fun () {...}] = Undetermined @@ -23,7 +25,9 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] = Undetermined UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String] UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] - ULiteralExpression (value = 42) [42] = 42 + UBlockExpression [{...}] = Nothing + UReturnExpression [return 42] = Undetermined + ULiteralExpression (value = 42) [42] = 42 UDeclarationsExpression [public static final class LocalObject {...}] = Undetermined UClass (name = LocalObject) [public static final class LocalObject {...}] UField (name = INSTANCE) [@null public static final var INSTANCE: LocalDeclarationsKt.foo.LocalObject]