From 2eb6f1988df4995d3ba74602a2b087e9c1c06d5c Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Sun, 22 Mar 2020 17:23:51 +0300 Subject: [PATCH] Uast: process `catch` parameters and `finally` blocks (KT-35804) --- .../uast/kotlin/KotlinUastLanguagePlugin.kt | 6 ++ .../kotlin/declarations/KotlinUVariable.kt | 1 + .../kotlin/expressions/KotlinUCatchClause.kt | 20 +++++- plugins/uast-kotlin/testData/TryCatch.kt | 32 ++++++++++ plugins/uast-kotlin/testData/TryCatch.log.txt | 61 +++++++++++++++++++ .../uast-kotlin/testData/TryCatch.render.txt | 42 +++++++++++++ .../tests/KotlinIDERenderLogTest.kt | 3 + .../tests/SimpleKotlinRenderLogTest.kt | 3 + 8 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 plugins/uast-kotlin/testData/TryCatch.kt create mode 100644 plugins/uast-kotlin/testData/TryCatch.log.txt create mode 100644 plugins/uast-kotlin/testData/TryCatch.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 1956f91af5d..a516b0140ed 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -43,6 +43,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.uast.* import org.jetbrains.uast.expressions.UInjectionHost import org.jetbrains.uast.kotlin.KotlinConverter.convertDeclaration @@ -195,6 +196,7 @@ internal object KotlinConverter { is KtLightParameterList -> unwrapElements(element.parent) is KtTypeElement -> unwrapElements(element.parent) is KtSuperTypeList -> unwrapElements(element.parent) + is KtFinallySection -> unwrapElements(element.parent) else -> element } @@ -626,6 +628,10 @@ internal object KotlinConverter { val lightParameter = lightMethod.parameterList.parameters.find { it.name == element.name } ?: return@uParam null KotlinUParameter(lightParameter, element, givenParent) }, + alternative catch@{ + val uCatchClause = element.parent?.parent?.safeAs()?.toUElementOfType() ?: return@catch null + uCatchClause.parameters.firstOrNull { it.sourcePsi == element } + }, *convertToPropertyAlternatives(LightClassUtil.getLightClassPropertyMethods(element), givenParent) ) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt index a90a01b67a1..a0ba6c20c0f 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt @@ -199,6 +199,7 @@ open class KotlinUParameter( override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean { if (sourcePsi !is KtParameter) return false if (isKtConstructorParam == isLightConstructorParam && target == null) return true + if (sourcePsi.parent.parent is KtCatchClause && target == null) return true when (target) { AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> return isLightConstructorParam == true AnnotationUseSiteTarget.SETTER_PARAMETER -> return isLightConstructorParam != true diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCatchClause.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCatchClause.kt index 8438f0f2876..daf55dbcb07 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCatchClause.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCatchClause.kt @@ -22,7 +22,9 @@ import org.jetbrains.uast.UCatchClause import org.jetbrains.uast.UElement import org.jetbrains.uast.UParameter import org.jetbrains.uast.UTypeReferenceExpression +import org.jetbrains.uast.internal.acceptList import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter +import org.jetbrains.uast.visitor.UastVisitor class KotlinUCatchClause( override val sourcePsi: KtCatchClause, @@ -34,15 +36,27 @@ class KotlinUCatchClause( override val javaPsi: PsiElement? get() = null override val body by lz { KotlinConverter.convertOrEmpty(sourcePsi.catchBody, this) } - + override val parameters by lz { val parameter = sourcePsi.catchParameter ?: return@lz emptyList() - listOf(KotlinUParameter(UastKotlinPsiParameter.create(parameter, sourcePsi, this, 0), sourcePsi, this)) + listOf(KotlinUParameter(UastKotlinPsiParameter.create(parameter, sourcePsi, this, 0), parameter, this)) } override val typeReferences by lz { val parameter = sourcePsi.catchParameter ?: return@lz emptyList() val typeReference = parameter.typeReference ?: return@lz emptyList() - listOf(LazyKotlinUTypeReferenceExpression(typeReference, this) { typeReference.toPsiType(this, boxed = true) } ) + listOf(LazyKotlinUTypeReferenceExpression(typeReference, this) { typeReference.toPsiType(this, boxed = true) }) } + + // equal to IDEA 202 implementation + override fun accept(visitor: UastVisitor) { + if (visitor.visitCatchClause(this)) return + parameters.acceptList(visitor) + body.accept(visitor) + visitor.afterVisitCatchClause(this) + } + + // equal to IDEA 202 implementation + override fun asRenderString(): String = "catch (${parameters.joinToString { it.asRenderString() }}) ${body.asRenderString()}" + } \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/TryCatch.kt b/plugins/uast-kotlin/testData/TryCatch.kt new file mode 100644 index 00000000000..faf598d4f91 --- /dev/null +++ b/plugins/uast-kotlin/testData/TryCatch.kt @@ -0,0 +1,32 @@ +class TryCatch { + fun catches() { + try { + body() + } catch (e: Throwable) { + catcher() + } finally { + finalizer() + } + } + + fun body() {} + fun catcher() {} + fun finalizer() {} +} + +class TryCatchAnnotations { + @java.lang.SuppressWarnings("Something") + fun catches() { + try { + body() + } catch (@java.lang.SuppressWarnings("Something") e: Throwable) { + catcher() + } finally { + finalizer() + } + } + + fun body() {} + fun catcher() {} + fun finalizer() {} +} diff --git a/plugins/uast-kotlin/testData/TryCatch.log.txt b/plugins/uast-kotlin/testData/TryCatch.log.txt new file mode 100644 index 00000000000..2a36b4ae4cb --- /dev/null +++ b/plugins/uast-kotlin/testData/TryCatch.log.txt @@ -0,0 +1,61 @@ +UFile (package = ) + UClass (name = TryCatch) + UMethod (name = catches) + UBlockExpression + UTryExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (body)) + USimpleNameReferenceExpression (identifier = body, resolvesTo = null) + UCatchClause (e) + UParameter (name = e) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (catcher)) + USimpleNameReferenceExpression (identifier = catcher, resolvesTo = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (finalizer)) + USimpleNameReferenceExpression (identifier = finalizer, resolvesTo = null) + UMethod (name = body) + UBlockExpression + UMethod (name = catcher) + UBlockExpression + UMethod (name = finalizer) + UBlockExpression + UMethod (name = TryCatch) + UClass (name = TryCatchAnnotations) + UMethod (name = catches) + UAnnotation (fqName = java.lang.SuppressWarnings) + UNamedExpression (name = value) + UPolyadicExpression (operator = +) + ULiteralExpression (value = "Something") + UBlockExpression + UTryExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (body)) + USimpleNameReferenceExpression (identifier = body, resolvesTo = null) + UCatchClause (e) + UParameter (name = e) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UAnnotation (fqName = java.lang.SuppressWarnings) + UNamedExpression (name = value) + UPolyadicExpression (operator = +) + ULiteralExpression (value = "Something") + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (catcher)) + USimpleNameReferenceExpression (identifier = catcher, resolvesTo = null) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (finalizer)) + USimpleNameReferenceExpression (identifier = finalizer, resolvesTo = null) + UMethod (name = body) + UBlockExpression + UMethod (name = catcher) + UBlockExpression + UMethod (name = finalizer) + UBlockExpression + UMethod (name = TryCatchAnnotations) diff --git a/plugins/uast-kotlin/testData/TryCatch.render.txt b/plugins/uast-kotlin/testData/TryCatch.render.txt new file mode 100644 index 00000000000..d727d59bce5 --- /dev/null +++ b/plugins/uast-kotlin/testData/TryCatch.render.txt @@ -0,0 +1,42 @@ +public final class TryCatch { + public final fun catches() : void { + try { + body() + } + catch (@org.jetbrains.annotations.NotNull var e: java.lang.Throwable) { + catcher() + } + finally { + finalizer() + } + } + public final fun body() : void { + } + public final fun catcher() : void { + } + public final fun finalizer() : void { + } + public fun TryCatch() = UastEmptyExpression +} + +public final class TryCatchAnnotations { + @java.lang.SuppressWarnings(value = "Something") + public final fun catches() : void { + try { + body() + } + catch (@org.jetbrains.annotations.NotNull @java.lang.SuppressWarnings(value = "Something") var e: java.lang.Throwable) { + catcher() + } + finally { + finalizer() + } + } + public final fun body() : void { + } + public final fun catcher() : void { + } + public final fun finalizer() : void { + } + public fun TryCatchAnnotations() = UastEmptyExpression +} diff --git a/plugins/uast-kotlin/tests/KotlinIDERenderLogTest.kt b/plugins/uast-kotlin/tests/KotlinIDERenderLogTest.kt index 20e740ccc79..e91f5fa1fff 100644 --- a/plugins/uast-kotlin/tests/KotlinIDERenderLogTest.kt +++ b/plugins/uast-kotlin/tests/KotlinIDERenderLogTest.kt @@ -163,4 +163,7 @@ class KotlinIDERenderLogTest : AbstractKotlinUastLightCodeInsightFixtureTest(), @Test fun testDeprecatedHidden() = doTest("DeprecatedHidden") + + @Test + fun testTryCatch() = doTest("TryCatch") } diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index cb3b277f8cc..042da94572a 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -141,6 +141,9 @@ class SimpleKotlinRenderLogTest : AbstractKotlinUastTest(), AbstractKotlinRender @Test fun testDeprecatedHidden() = doTest("DeprecatedHidden") + + @Test + fun testTryCatch() = doTest("TryCatch") } fun withForceUInjectionHostValue(call: () -> Unit) {