diff --git a/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt b/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt index 53b8569582f1..f0d8da743a07 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt @@ -20,10 +20,8 @@ import org.jetbrains.uast.* import org.jetbrains.uast.analysis.UastAnalysisPlugin import org.jetbrains.uast.java.JavaConverter.convertPsiElement import org.jetbrains.uast.java.declarations.JavaLazyParentUIdentifier -import org.jetbrains.uast.java.expressions.JavaUAnnotationCallExpression +import org.jetbrains.uast.java.expressions.* import org.jetbrains.uast.java.expressions.JavaUModuleReferenceExpression -import org.jetbrains.uast.java.expressions.JavaUNamedExpression -import org.jetbrains.uast.java.expressions.JavaUSynchronizedExpression import org.jetbrains.uast.util.ClassSet import org.jetbrains.uast.util.ClassSetsWrapper @@ -319,6 +317,14 @@ internal object JavaConverter { override fun visitResourceList(resourceList: PsiResourceList) { result = true } + + override fun visitDeconstructionList(deconstructionList: PsiDeconstructionList) { + result = true + } + + override fun visitPatternVariable(variable: PsiPatternVariable) { + result = true + } } element.accept(visitor) @@ -411,6 +417,19 @@ internal object JavaConverter { override fun visitComment(comment: PsiComment) { result = requiredType.el(comment, givenParent, ::UComment) } + + override fun visitTypeTestPattern(pattern: PsiTypeTestPattern) { + result = requiredType.expr(pattern, givenParent, ::JavaUTypePatternExpression) + } + + override fun visitUnnamedPattern(pattern: PsiUnnamedPattern) { + result = requiredType.expr(pattern, givenParent, ::JavaUUnamedPatternExpression) + } + + override fun visitDeconstructionPattern(deconstructionPattern: PsiDeconstructionPattern) { + result = requiredType.expr(deconstructionPattern, givenParent, + ::JavaUDeconstructionPatternPattern) + } } el.accept(visitor) @@ -464,8 +483,12 @@ internal object JavaConverter { } override fun visitInstanceOfExpression(expression: PsiInstanceOfExpression) { - result = requiredType.expr(expression, givenParent, - ::JavaUInstanceCheckExpression) + result = if (expression.pattern != null) { + requiredType.expr(expression, givenParent, + ::JavaUInstanceWithPatternExpression) + } else { + requiredType.expr(expression, givenParent, ::JavaUInstanceCheckExpression) + } } override fun visitLambdaExpression(expression: PsiLambdaExpression) { diff --git a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt index c3db7e4e71d6..772cb2f8b955 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/controlStructures/JavaUSwitchExpression.kt @@ -130,8 +130,7 @@ class JavaUSwitchEntry( } else { it.caseLabelElementList?.elements.orEmpty().map { element -> - if (element is PsiExpression) JavaConverter.convertOrEmpty(element, this) - else UnknownJavaExpression(element, this) + JavaConverter.convertPsiElement(element, this, UExpression::class.java) as? UExpression ?: UnknownJavaExpression(element, this) } } } diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceWithPatternExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceWithPatternExpression.kt new file mode 100644 index 000000000000..f84fb83709bf --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUInstanceWithPatternExpression.kt @@ -0,0 +1,30 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.uast.java.expressions + +import com.intellij.psi.PsiInstanceOfExpression +import com.intellij.psi.PsiType +import com.intellij.psi.PsiTypes +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.uast.* +import org.jetbrains.uast.java.JavaAbstractUExpression +import org.jetbrains.uast.java.JavaConverter + +@ApiStatus.Internal +class JavaUInstanceWithPatternExpression( + override val sourcePsi: PsiInstanceOfExpression, + givenParent: UElement? +) : JavaAbstractUExpression(givenParent), UBinaryExpressionWithPattern { + private val operandPart = UastLazyPart() + + private val patternPart = UastLazyPart() + + override val operand: UExpression get() = operandPart.getOrBuild { JavaConverter.convertOrEmpty(sourcePsi.operand, this) } + + override val patternExpression: UPatternExpression? get() = patternPart.getOrBuild { + sourcePsi.pattern?.let { pattern -> + JavaConverter.convertPsiElement(pattern, this, UPatternExpression::class.java) as? UPatternExpression + } + } + + override fun getExpressionType(): PsiType = PsiTypes.booleanType() +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPatternExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPatternExpression.kt new file mode 100644 index 000000000000..27e951f3d5d0 --- /dev/null +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUPatternExpression.kt @@ -0,0 +1,62 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.uast.java.expressions + +import com.intellij.psi.PsiDeconstructionPattern +import com.intellij.psi.PsiTypeTestPattern +import com.intellij.psi.PsiUnnamedPattern +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.uast.* +import org.jetbrains.uast.java.JavaAbstractUExpression +import org.jetbrains.uast.java.JavaConverter +import org.jetbrains.uast.java.JavaUTypeReferenceExpression + +@ApiStatus.Internal +class JavaUUnamedPatternExpression( + override val sourcePsi: PsiUnnamedPattern, + givenParent: UElement? +) : JavaAbstractUExpression(givenParent), UPatternExpression { + override val name: String? = null + + override val typeReference: UTypeReferenceExpression? = null + + override val deconstructedPatterns: List = emptyList() +} + +@ApiStatus.Internal +class JavaUTypePatternExpression( + override val sourcePsi: PsiTypeTestPattern, + givenParent: UElement? +) : JavaAbstractUExpression(givenParent), UPatternExpression { + private val typeReferencePart = UastLazyPart() + + override val name: String? = sourcePsi.patternVariable?.name + + override val deconstructedPatterns: List = emptyList() + + override val typeReference: UTypeReferenceExpression? = typeReferencePart.getOrBuild { + sourcePsi.checkType?.let { typeElem -> JavaUTypeReferenceExpression(typeElem, this) } + } +} + +@ApiStatus.Internal +class JavaUDeconstructionPatternPattern( + override val sourcePsi: PsiDeconstructionPattern, + givenParent: UElement? +) : JavaAbstractUExpression(givenParent), UPatternExpression { + private val typeReferencePart = UastLazyPart() + + private val patternsPart = UastLazyPart>() + + override val name: String? = null + + override val deconstructedPatterns: List + get() = patternsPart.getOrBuild { + sourcePsi.deconstructionList.deconstructionComponents.mapNotNull { component -> + JavaConverter.convertPsiElement(component, this, UPatternExpression::class.java) as? UPatternExpression + } + } + + override val typeReference: UTypeReferenceExpression = typeReferencePart.getOrBuild { + JavaUTypeReferenceExpression(sourcePsi.typeElement, this) + } +} \ No newline at end of file diff --git a/uast/uast-java/src/org/jetbrains/uast/java/psiElementMapping.kt b/uast/uast-java/src/org/jetbrains/uast/java/psiElementMapping.kt index 7f91ce3dcc24..730df19c6543 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/psiElementMapping.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/psiElementMapping.kt @@ -133,7 +133,10 @@ private val possibleSourceTypes = mapOf, ClassSet>( PsiWhileStatement::class.java, PsiYieldStatement::class.java, PsiRecordComponent::class.java, - PsiRecordHeader::class.java + PsiRecordHeader::class.java, + PsiUnnamedPattern::class.java, + PsiTypeTestPattern::class.java, + PsiDeconstructionPattern::class.java ), UAnnotation::class.java to classSetOf( PsiAnnotation::class.java @@ -332,7 +335,10 @@ private val possibleSourceTypes = mapOf, ClassSet>( PsiWhileStatement::class.java, PsiYieldStatement::class.java, PsiRecordComponent::class.java, - PsiRecordHeader::class.java + PsiRecordHeader::class.java, + PsiUnnamedPattern::class.java, + PsiTypeTestPattern::class.java, + PsiDeconstructionPattern::class.java ), UElementWithLocation::class.java to classSetOf( //PsiExpressionStatement::class.java, @@ -344,6 +350,11 @@ private val possibleSourceTypes = mapOf, ClassSet>( UEnumConstantEx::class.java to classSetOf( PsiEnumConstant::class.java ), + UPatternExpression::class.java to classSetOf( + PsiUnnamedPattern::class.java, + PsiTypeTestPattern::class.java, + PsiDeconstructionPattern::class.java + ), UExpression::class.java to classSetOf( PsiAnnotatedJavaCodeReferenceElement::class.java, PsiAnnotation::class.java, @@ -397,7 +408,10 @@ private val possibleSourceTypes = mapOf, ClassSet>( PsiTypeCastExpression::class.java, PsiTypeElement::class.java, PsiWhileStatement::class.java, - PsiYieldStatement::class.java + PsiYieldStatement::class.java, + PsiUnnamedPattern::class.java, + PsiTypeTestPattern::class.java, + PsiDeconstructionPattern::class.java ), UExpressionList::class.java to classSetOf( ), diff --git a/uast/uast-tests/java/Simple/InstanceOfRecordPattern.java b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.java new file mode 100644 index 000000000000..aaf4a34509b0 --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.java @@ -0,0 +1,15 @@ +public class RecordPattern { + public static void main(String[] args) { + Box b = new Box<>(new RedBall()); + if (b instanceof Box(RedBall a)) { } + if (b instanceof Box(GreenBall _)) { } + if (b instanceof Box(_)) { } + } +} + +record Box(T content) { } + +sealed abstract class Ball permits RedBall, BlueBall, GreenBall { } +final class RedBall extends Ball { } +final class BlueBall extends Ball { } +final class GreenBall extends Ball { } \ No newline at end of file diff --git a/uast/uast-tests/java/Simple/InstanceOfRecordPattern.log.txt b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.log.txt new file mode 100644 index 000000000000..953d83ac370c --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.log.txt @@ -0,0 +1,46 @@ +UFile (package = ) + UClass (name = RecordPattern) + UMethod (name = main) + UParameter (name = args) + UBlockExpression + UDeclarationsExpression + ULocalVariable (name = b) + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + USimpleNameReferenceExpression (identifier = Box) + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + USimpleNameReferenceExpression (identifier = RedBall) + UIfExpression + UBinaryExpressionWithPattern + USimpleNameReferenceExpression (identifier = b) + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UTypeReferenceExpression (name = RedBall) + UBlockExpression + UastEmptyExpression + UIfExpression + UBinaryExpressionWithPattern + USimpleNameReferenceExpression (identifier = b) + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UTypeReferenceExpression (name = GreenBall) + UBlockExpression + UastEmptyExpression + UIfExpression + UBinaryExpressionWithPattern + USimpleNameReferenceExpression (identifier = b) + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UBlockExpression + UastEmptyExpression + UClass (name = Box) + UField (name = content) + UMethod (name = content) + UMethod (name = Box) + UParameter (name = content) + UClass (name = Ball) + UClass (name = RedBall) + UClass (name = BlueBall) + UClass (name = GreenBall) diff --git a/uast/uast-tests/java/Simple/InstanceOfRecordPattern.render.txt b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.render.txt new file mode 100644 index 000000000000..cfdac6f5ccfb --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfRecordPattern.render.txt @@ -0,0 +1,29 @@ +public class RecordPattern { + public static fun main(args: java.lang.String[]) : void { + var b: Box = Box(RedBall()) + if (b is Box(RedBall a) _) { + } + if (b is Box(GreenBall _) _) { + } + if (b is Box(_) _) { + } + } +} + +final class Box { + private final var content: T + public fun content() : T = UastEmptyExpression + fun Box(content: T) = UastEmptyExpression +} + +abstract sealed class Ball { +} + +final class RedBall : Ball { +} + +final class BlueBall : Ball { +} + +final class GreenBall : Ball { +} diff --git a/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.java b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.java new file mode 100644 index 000000000000..ae87ba0954e5 --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.java @@ -0,0 +1,5 @@ +public class TypePattern { + public static int foo(Number x) { + if (x instanceof Integer y) { } + } +} \ No newline at end of file diff --git a/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.log.txt b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.log.txt new file mode 100644 index 000000000000..cf15dddec125 --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.log.txt @@ -0,0 +1,12 @@ +UFile (package = ) + UClass (name = TypePattern) + UMethod (name = foo) + UParameter (name = x) + UBlockExpression + UIfExpression + UBinaryExpressionWithPattern + USimpleNameReferenceExpression (identifier = x) + UPatternExpression + UTypeReferenceExpression (name = java.lang.Integer) + UBlockExpression + UastEmptyExpression diff --git a/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.render.txt b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.render.txt new file mode 100644 index 000000000000..2000de884116 --- /dev/null +++ b/uast/uast-tests/java/Simple/InstanceOfTypeTestPattern.render.txt @@ -0,0 +1,6 @@ +public class TypePattern { + public static fun foo(x: java.lang.Number) : int { + if (x is java.lang.Integer y) { + } + } +} diff --git a/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.java b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.java new file mode 100644 index 000000000000..93268906d68d --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.java @@ -0,0 +1,17 @@ +public class TypePattern { + public static int foo(Number x) { + Box b = new Box<>(null); + switch (b) { + case Box(RedBall _), Box(BlueBall _) -> System.out.println("red or blue"); + case Box(GreenBall a) -> System.out.println("green"); + case Box(_) -> System.out.println("null"); + } + } +} + +record Box(T content) { } + +sealed abstract class Ball permits RedBall, BlueBall, GreenBall { } +final class RedBall extends Ball { } +final class BlueBall extends Ball { } +final class GreenBall extends Ball { } \ No newline at end of file diff --git a/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.log.txt b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.log.txt new file mode 100644 index 000000000000..ad2872bb9676 --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.log.txt @@ -0,0 +1,67 @@ +UFile (package = ) + UClass (name = TypePattern) + UMethod (name = foo) + UParameter (name = x) + UBlockExpression + UDeclarationsExpression + ULocalVariable (name = b) + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) + USimpleNameReferenceExpression (identifier = Box) + ULiteralExpression (value = null) + USwitchExpression + USimpleNameReferenceExpression (identifier = b) + UExpressionList (switch) + USwitchClauseExpressionWithBody + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UTypeReferenceExpression (name = RedBall) + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UTypeReferenceExpression (name = BlueBall) + UExpressionList (switch_entry) + UYieldExpression + UQualifiedReferenceExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = System) + USimpleNameReferenceExpression (identifier = out) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + ULiteralExpression (value = "red or blue") + USwitchClauseExpressionWithBody + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UTypeReferenceExpression (name = GreenBall) + UExpressionList (switch_entry) + UYieldExpression + UQualifiedReferenceExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = System) + USimpleNameReferenceExpression (identifier = out) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + ULiteralExpression (value = "green") + USwitchClauseExpressionWithBody + UPatternExpression + UTypeReferenceExpression (name = Box) + UPatternExpression + UExpressionList (switch_entry) + UYieldExpression + UQualifiedReferenceExpression + UQualifiedReferenceExpression + USimpleNameReferenceExpression (identifier = System) + USimpleNameReferenceExpression (identifier = out) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) + UIdentifier (Identifier (println)) + ULiteralExpression (value = "null") + UClass (name = Box) + UField (name = content) + UMethod (name = content) + UMethod (name = Box) + UParameter (name = content) + UClass (name = Ball) + UClass (name = RedBall) + UClass (name = BlueBall) + UClass (name = GreenBall) diff --git a/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.render.txt b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.render.txt new file mode 100644 index 000000000000..f0a9bcb861b1 --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseRecordPattern.render.txt @@ -0,0 +1,37 @@ +public class TypePattern { + public static fun foo(x: java.lang.Number) : int { + var b: Box = Box(null) + switch (b) + Box(RedBall _) _, Box(BlueBall _) _ -> { + yield System.out.println("red or blue") + } + + Box(GreenBall a) _ -> { + yield System.out.println("green") + } + + Box(_) _ -> { + yield System.out.println("null") + } + + + } +} + +final class Box { + private final var content: T + public fun content() : T = UastEmptyExpression + fun Box(content: T) = UastEmptyExpression +} + +abstract sealed class Ball { +} + +final class RedBall : Ball { +} + +final class BlueBall : Ball { +} + +final class GreenBall : Ball { +} diff --git a/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.java b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.java new file mode 100644 index 000000000000..d249cd8c6756 --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.java @@ -0,0 +1,7 @@ +public class TypePattern { + public static int foo(Number x) { + switch (x) { + case Integer i -> { } + } + } +} \ No newline at end of file diff --git a/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.log.txt b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.log.txt new file mode 100644 index 000000000000..3741af9ee2ac --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.log.txt @@ -0,0 +1,12 @@ +UFile (package = ) + UClass (name = TypePattern) + UMethod (name = foo) + UParameter (name = x) + UBlockExpression + USwitchExpression + USimpleNameReferenceExpression (identifier = x) + UExpressionList (switch) + USwitchClauseExpressionWithBody + UPatternExpression + UTypeReferenceExpression (name = java.lang.Integer) + UExpressionList (switch_entry) diff --git a/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.render.txt b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.render.txt new file mode 100644 index 000000000000..23ca5dc71550 --- /dev/null +++ b/uast/uast-tests/java/Simple/SwitchCaseTypeTestPattern.render.txt @@ -0,0 +1,9 @@ +public class TypePattern { + public static fun foo(x: java.lang.Number) : int { + switch (x) + java.lang.Integer i -> { + } + + + } +} diff --git a/uast/uast-tests/test/org/jetbrains/uast/test/java/SimpleJavaRenderLogTest.kt b/uast/uast-tests/test/org/jetbrains/uast/test/java/SimpleJavaRenderLogTest.kt index 86e59c61b5eb..6c0d84267d72 100644 --- a/uast/uast-tests/test/org/jetbrains/uast/test/java/SimpleJavaRenderLogTest.kt +++ b/uast/uast-tests/test/org/jetbrains/uast/test/java/SimpleJavaRenderLogTest.kt @@ -78,5 +78,14 @@ class SimpleJavaRenderLogTest : AbstractJavaRenderLogTest(), RenderLogTestBase { fun testRecord() = doTest("Simple/Record.java") @Test - fun testTypeAnnotations() = doTest("Simple/TypeAnnotations.java") + fun testInstanceOfTypeTestPattern() = doTest("Simple/InstanceOfTypeTestPattern.java") + + @Test + fun testInstanceOfRecordPattern() = doTest("Simple/InstanceOfRecordPattern.java") + + @Test + fun testSwitchCaseTypeTestPattern() = doTest("Simple/SwitchCaseTypeTestPattern.java") + + @Test + fun testSwitchCaseRecordPattern() = doTest("Simple/SwitchCaseRecordPattern.java") } \ No newline at end of file