From 872b140500a19ef2e3738013a1d07f26be79c5ea Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Fri, 27 Mar 2020 15:56:10 +0300 Subject: [PATCH] Uast: support for annotated expressions (KT-35801) --- .../uast/kotlin/KotlinAbstractUElement.kt | 11 ++--- .../uast/kotlin/KotlinUastLanguagePlugin.kt | 6 +++ .../kotlin/declarations/KotlinUAnnotation.kt | 5 +++ .../kotlin/declarations/KotlinUVariable.kt | 2 +- .../kotlin/expressions/ElvisExpression.kt | 2 +- .../KotlinUFunctionCallExpression.kt | 1 + .../KotlinUSimpleReferenceExpression.kt | 6 +++ .../testData/AnnotatedExpressions.kt | 23 +++++++++++ .../testData/AnnotatedExpressions.log.txt | 40 +++++++++++++++++++ .../testData/AnnotatedExpressions.render.txt | 13 ++++++ plugins/uast-kotlin/testData/Elvis.log.txt | 2 - plugins/uast-kotlin/testData/Elvis.render.txt | 4 +- .../testData/TypeReferences.log.txt | 1 - .../testData/TypeReferences.render.txt | 2 +- .../tests/SimpleKotlinRenderLogTest.kt | 3 ++ 15 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 plugins/uast-kotlin/testData/AnnotatedExpressions.kt create mode 100644 plugins/uast-kotlin/testData/AnnotatedExpressions.log.txt create mode 100644 plugins/uast-kotlin/testData/AnnotatedExpressions.render.txt 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 610da7a5a2c..21f705ad60e 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt @@ -206,11 +206,12 @@ fun doConvertParent(element: UElement, parent: PsiElement?): UElement? { return result.tempVarAssignment } - if (result is KotlinUElvisExpression && parent is KtBinaryExpression) { - when (element.psi) { - parent.left -> return result.lhsDeclaration - parent.right -> return result.rhsIfExpression - } + if (result is KotlinUElvisExpression && parentUnwrapped is KtBinaryExpression) { + val branch: Sequence = element.psi?.parentsWithSelf.orEmpty().takeWhile { it != parentUnwrapped } + if (branch.contains(parentUnwrapped.left)) + return result.lhsDeclaration + if (branch.contains(parentUnwrapped.right)) + return result.rhsIfExpression } if ((result is UMethod || result is KotlinLocalFunctionULambdaExpression) 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 4c8ee6657c1..13eb45f594e 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -198,6 +198,7 @@ internal object KotlinConverter { is KtTypeElement -> unwrapElements(element.parent) is KtSuperTypeList -> unwrapElements(element.parent) is KtFinallySection -> unwrapElements(element.parent) + is KtAnnotatedExpression -> unwrapElements(element.parent) else -> element } @@ -422,6 +423,11 @@ internal object KotlinConverter { else { expr(build(::createLocalFunctionDeclaration)) } + is KtAnnotatedExpression -> { + expression.baseExpression + ?.let { convertExpression(it, givenParent, requiredType) } + ?: expr(build(::UnknownKotlinExpression)) + } else -> expr(build(::UnknownKotlinExpression)) }} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt index fdc2a6a49fd..6bf95447287 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.uast.* import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier import org.jetbrains.uast.kotlin.declarations.KotlinUMethod @@ -94,6 +95,10 @@ abstract class KotlinUAnnotationBase( } override fun convertParent(): UElement? { + sourcePsi.parent.safeAs()?.let { + return it.baseExpression?.let { KotlinConverter.convertExpression(it, null, DEFAULT_EXPRESSION_TYPES_LIST) } + } + val superParent = super.convertParent() ?: return null if (annotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER) { (superParent.uastParent as? KotlinUMethod)?.uastParameters?.firstIsInstance()?.let { 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 a0ba6c20c0f..3caf8a81cd3 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 @@ -337,7 +337,7 @@ open class KotlinUField( open class KotlinULocalVariable( psi: PsiLocalVariable, - override val sourcePsi: KtElement, + override val sourcePsi: KtElement?, givenParent: UElement? ) : AbstractKotlinUVariable(givenParent), ULocalVariableExPlaceHolder, PsiLocalVariable by psi { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt index 9e2f4bf193c..89cb7f7f247 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt @@ -57,7 +57,7 @@ private fun createElvisExpressions( psiParent: PsiElement): List { val declaration = KotlinUDeclarationsExpression(containingElement) - val tempVariable = KotlinULocalVariable(UastKotlinPsiVariable.create(left, declaration, psiParent), left, declaration) + val tempVariable = KotlinULocalVariable(UastKotlinPsiVariable.create(left, declaration, psiParent), null, declaration) declaration.declarations = listOf(tempVariable) val ifExpression = object : UIfExpression, JvmDeclarationUElementPlaceholder { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt index b5306f45c5e..46fa81c660f 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt @@ -192,6 +192,7 @@ class KotlinUFunctionCallExpression( override fun accept(visitor: UastVisitor) { if (visitor.visitCallExpression(this)) return + annotations.acceptList(visitor) methodIdentifier?.accept(visitor) classReference.accept(visitor) valueArguments.acceptList(visitor) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt index 19ee8f64687..96375430285 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.utils.addToStdlib.constant import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList import org.jetbrains.uast.internal.log import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve @@ -81,6 +82,7 @@ open class KotlinUSimpleReferenceExpression( if (sourcePsi.parent.destructuringDeclarationInitializer != true) { visitAccessorCalls(visitor) } + annotations.acceptList(visitor) visitor.afterVisitSimpleNameReferenceExpression(this) } @@ -238,6 +240,10 @@ class KotlinClassViaConstructorUSimpleReferenceExpression( } } + override fun accept(visitor: UastVisitor) { + super.accept(visitor) + } + override fun resolve(): PsiElement? = resolved override fun asLogString(): String = log("identifier = $identifier, resolvesTo = $resolvedName") diff --git a/plugins/uast-kotlin/testData/AnnotatedExpressions.kt b/plugins/uast-kotlin/testData/AnnotatedExpressions.kt new file mode 100644 index 00000000000..edad5ec9b2b --- /dev/null +++ b/plugins/uast-kotlin/testData/AnnotatedExpressions.kt @@ -0,0 +1,23 @@ +fun foo() { + + @Suppress + foo() + + @Suppress + val a = 1 + + @Suppress + var b = 2 + + @Suppress + b = a + + @Suppress + if (a > 2) + a + else + b + + val c = @Suppress a ?: b + +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/AnnotatedExpressions.log.txt b/plugins/uast-kotlin/testData/AnnotatedExpressions.log.txt new file mode 100644 index 00000000000..fe94409fe00 --- /dev/null +++ b/plugins/uast-kotlin/testData/AnnotatedExpressions.log.txt @@ -0,0 +1,40 @@ +UFile (package = ) + UClass (name = AnnotatedExpressionsKt) + UMethod (name = foo) + UBlockExpression + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UAnnotation (fqName = kotlin.Suppress) + UIdentifier (Identifier (foo)) + USimpleNameReferenceExpression (identifier = foo, resolvesTo = null) + UDeclarationsExpression + ULocalVariable (name = a) + UAnnotation (fqName = kotlin.Suppress) + ULiteralExpression (value = 1) + UDeclarationsExpression + ULocalVariable (name = b) + UAnnotation (fqName = kotlin.Suppress) + ULiteralExpression (value = 2) + UBinaryExpression (operator = =) + UAnnotation (fqName = kotlin.Suppress) + USimpleNameReferenceExpression (identifier = b) + USimpleNameReferenceExpression (identifier = a) + UIfExpression + UAnnotation (fqName = kotlin.Suppress) + UBinaryExpression (operator = >) + USimpleNameReferenceExpression (identifier = a) + ULiteralExpression (value = 2) + USimpleNameReferenceExpression (identifier = a) + USimpleNameReferenceExpression (identifier = b) + UDeclarationsExpression + ULocalVariable (name = c) + UExpressionList (elvis) + UDeclarationsExpression + ULocalVariable (name = varae507364) + USimpleNameReferenceExpression (identifier = a) + UAnnotation (fqName = kotlin.Suppress) + UIfExpression + UBinaryExpression (operator = !=) + USimpleNameReferenceExpression (identifier = varae507364) + ULiteralExpression (value = null) + USimpleNameReferenceExpression (identifier = varae507364) + USimpleNameReferenceExpression (identifier = b) diff --git a/plugins/uast-kotlin/testData/AnnotatedExpressions.render.txt b/plugins/uast-kotlin/testData/AnnotatedExpressions.render.txt new file mode 100644 index 00000000000..fac12e18f9b --- /dev/null +++ b/plugins/uast-kotlin/testData/AnnotatedExpressions.render.txt @@ -0,0 +1,13 @@ +public final class AnnotatedExpressionsKt { + public static final fun foo() : void { + foo() + @kotlin.Suppress var a: int = 1 + @kotlin.Suppress var b: int = 2 + b = a + if (a > 2) a else b + var c: int = elvis { + var varae507364: int = a + if (varae507364 != null) varae507364 else b + } + } +} diff --git a/plugins/uast-kotlin/testData/Elvis.log.txt b/plugins/uast-kotlin/testData/Elvis.log.txt index 98996672068..de6992a14f9 100644 --- a/plugins/uast-kotlin/testData/Elvis.log.txt +++ b/plugins/uast-kotlin/testData/Elvis.log.txt @@ -16,11 +16,9 @@ UFile (package = ) UExpressionList (elvis) UDeclarationsExpression ULocalVariable (name = var243c51a0) - UAnnotation (fqName = null) UExpressionList (elvis) UDeclarationsExpression ULocalVariable (name = varc4aef569) - UAnnotation (fqName = null) UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) UIdentifier (Identifier (foo)) USimpleNameReferenceExpression (identifier = foo, resolvesTo = null) diff --git a/plugins/uast-kotlin/testData/Elvis.render.txt b/plugins/uast-kotlin/testData/Elvis.render.txt index 49086e35368..2554f7d42fa 100644 --- a/plugins/uast-kotlin/testData/Elvis.render.txt +++ b/plugins/uast-kotlin/testData/Elvis.render.txt @@ -7,8 +7,8 @@ public final class ElvisKt { } public static final fun baz() : java.lang.String { return elvis { - @null var var243c51a0: java.lang.String = elvis { - @null var varc4aef569: java.lang.String = foo("Lorem ipsum") + var var243c51a0: java.lang.String = elvis { + var varc4aef569: java.lang.String = foo("Lorem ipsum") if (varc4aef569 != null) varc4aef569 else foo("dolor sit amet") } if (var243c51a0 != null) var243c51a0 else bar().toString() diff --git a/plugins/uast-kotlin/testData/TypeReferences.log.txt b/plugins/uast-kotlin/testData/TypeReferences.log.txt index 2fff6b7146f..ba3d2505dc8 100644 --- a/plugins/uast-kotlin/testData/TypeReferences.log.txt +++ b/plugins/uast-kotlin/testData/TypeReferences.log.txt @@ -31,7 +31,6 @@ UFile (package = ) UExpressionList (elvis) UDeclarationsExpression ULocalVariable (name = var708e23eb) - UAnnotation (fqName = org.jetbrains.annotations.Nullable) USimpleNameReferenceExpression (identifier = arg) UIfExpression UBinaryExpression (operator = !=) diff --git a/plugins/uast-kotlin/testData/TypeReferences.render.txt b/plugins/uast-kotlin/testData/TypeReferences.render.txt index 2e7724af469..a248e77f998 100644 --- a/plugins/uast-kotlin/testData/TypeReferences.render.txt +++ b/plugins/uast-kotlin/testData/TypeReferences.render.txt @@ -8,7 +8,7 @@ public final class TypeReferencesKt { public static final fun parameterizedFoo(@org.jetbrains.annotations.Nullable arg: T) : void { var a: T = arg var at: T = elvis { - @org.jetbrains.annotations.Nullable var var708e23eb: T = arg + var var708e23eb: T = arg if (var708e23eb != null) var708e23eb else return } var tl: java.util.List = listOf(at) diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index 042da94572a..549ed909334 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -144,6 +144,9 @@ class SimpleKotlinRenderLogTest : AbstractKotlinUastTest(), AbstractKotlinRender @Test fun testTryCatch() = doTest("TryCatch") + + @Test + fun testAnnotatedExpressions() = doTest("AnnotatedExpressions") } fun withForceUInjectionHostValue(call: () -> Unit) {