mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[uast-java] Add support for pattern matching
#IDEA-310333 Fixed GitOrigin-RevId: 31fa57a0fdc5efcdfc419cd56ccc783f682234ce
This commit is contained in:
committed by
intellij-monorepo-bot
parent
992ce073b4
commit
6d55bf058d
@@ -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<UComment,PsiComment>(comment, givenParent, ::UComment)
|
||||
}
|
||||
|
||||
override fun visitTypeTestPattern(pattern: PsiTypeTestPattern) {
|
||||
result = requiredType.expr<UPatternExpression, PsiTypeTestPattern>(pattern, givenParent, ::JavaUTypePatternExpression)
|
||||
}
|
||||
|
||||
override fun visitUnnamedPattern(pattern: PsiUnnamedPattern) {
|
||||
result = requiredType.expr<UPatternExpression, PsiUnnamedPattern>(pattern, givenParent, ::JavaUUnamedPatternExpression)
|
||||
}
|
||||
|
||||
override fun visitDeconstructionPattern(deconstructionPattern: PsiDeconstructionPattern) {
|
||||
result = requiredType.expr<UPatternExpression, PsiDeconstructionPattern>(deconstructionPattern, givenParent,
|
||||
::JavaUDeconstructionPatternPattern)
|
||||
}
|
||||
}
|
||||
|
||||
el.accept(visitor)
|
||||
@@ -464,8 +483,12 @@ internal object JavaConverter {
|
||||
}
|
||||
|
||||
override fun visitInstanceOfExpression(expression: PsiInstanceOfExpression) {
|
||||
result = requiredType.expr<UBinaryExpressionWithType, PsiInstanceOfExpression>(expression, givenParent,
|
||||
::JavaUInstanceCheckExpression)
|
||||
result = if (expression.pattern != null) {
|
||||
requiredType.expr<UBinaryExpressionWithType, PsiInstanceOfExpression>(expression, givenParent,
|
||||
::JavaUInstanceWithPatternExpression)
|
||||
} else {
|
||||
requiredType.expr<UBinaryExpressionWithPattern, PsiInstanceOfExpression>(expression, givenParent, ::JavaUInstanceCheckExpression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLambdaExpression(expression: PsiLambdaExpression) {
|
||||
|
||||
+1
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -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<UExpression>()
|
||||
|
||||
private val patternPart = UastLazyPart<UPatternExpression?>()
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -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<UPatternExpression> = emptyList()
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
class JavaUTypePatternExpression(
|
||||
override val sourcePsi: PsiTypeTestPattern,
|
||||
givenParent: UElement?
|
||||
) : JavaAbstractUExpression(givenParent), UPatternExpression {
|
||||
private val typeReferencePart = UastLazyPart<UTypeReferenceExpression?>()
|
||||
|
||||
override val name: String? = sourcePsi.patternVariable?.name
|
||||
|
||||
override val deconstructedPatterns: List<UPatternExpression> = 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<UTypeReferenceExpression>()
|
||||
|
||||
private val patternsPart = UastLazyPart<List<UPatternExpression>>()
|
||||
|
||||
override val name: String? = null
|
||||
|
||||
override val deconstructedPatterns: List<UPatternExpression>
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,10 @@ private val possibleSourceTypes = mapOf<Class<*>, ClassSet<PsiElement>>(
|
||||
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<PsiElement>(
|
||||
PsiAnnotation::class.java
|
||||
@@ -332,7 +335,10 @@ private val possibleSourceTypes = mapOf<Class<*>, ClassSet<PsiElement>>(
|
||||
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<PsiElement>(
|
||||
//PsiExpressionStatement::class.java,
|
||||
@@ -344,6 +350,11 @@ private val possibleSourceTypes = mapOf<Class<*>, ClassSet<PsiElement>>(
|
||||
UEnumConstantEx::class.java to classSetOf<PsiElement>(
|
||||
PsiEnumConstant::class.java
|
||||
),
|
||||
UPatternExpression::class.java to classSetOf<PsiElement>(
|
||||
PsiUnnamedPattern::class.java,
|
||||
PsiTypeTestPattern::class.java,
|
||||
PsiDeconstructionPattern::class.java
|
||||
),
|
||||
UExpression::class.java to classSetOf<PsiElement>(
|
||||
PsiAnnotatedJavaCodeReferenceElement::class.java,
|
||||
PsiAnnotation::class.java,
|
||||
@@ -397,7 +408,10 @@ private val possibleSourceTypes = mapOf<Class<*>, ClassSet<PsiElement>>(
|
||||
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<PsiElement>(
|
||||
),
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
public class RecordPattern {
|
||||
public static void main(String[] args) {
|
||||
Box<Ball> b = new Box<>(new RedBall());
|
||||
if (b instanceof Box(RedBall a)) { }
|
||||
if (b instanceof Box(GreenBall _)) { }
|
||||
if (b instanceof Box(_)) { }
|
||||
}
|
||||
}
|
||||
|
||||
record Box<T extends Ball>(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 { }
|
||||
@@ -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)
|
||||
@@ -0,0 +1,29 @@
|
||||
public class RecordPattern {
|
||||
public static fun main(args: java.lang.String[]) : void {
|
||||
var b: Box<Ball> = 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 {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
public class TypePattern {
|
||||
public static int foo(Number x) {
|
||||
if (x instanceof Integer y) { }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
public class TypePattern {
|
||||
public static fun foo(x: java.lang.Number) : int {
|
||||
if (x is java.lang.Integer y) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
public class TypePattern {
|
||||
public static int foo(Number x) {
|
||||
Box<Ball> 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 extends Ball>(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 { }
|
||||
@@ -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)
|
||||
@@ -0,0 +1,37 @@
|
||||
public class TypePattern {
|
||||
public static fun foo(x: java.lang.Number) : int {
|
||||
var b: Box<Ball> = 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 {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class TypePattern {
|
||||
public static int foo(Number x) {
|
||||
switch (x) {
|
||||
case Integer i -> { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -0,0 +1,9 @@
|
||||
public class TypePattern {
|
||||
public static fun foo(x: java.lang.Number) : int {
|
||||
switch (x)
|
||||
java.lang.Integer i -> {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user