From 1e9963ae7d240960ce150b41da680e6f6b6e29db Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Fri, 30 Nov 2018 13:06:26 +0300 Subject: [PATCH] [uast-java] Support for converting Java 12 "enhanced" switch expressions (IDEA-202555) --- .../uast/java/JavaAbstractUElement.kt | 12 ++++- .../uast/java/JavaUastLanguagePlugin.kt | 5 +- .../JavaUSwitchExpression.kt | 24 +++++---- .../java/Simple/EnhancedSwitch.java | 27 ++++++++++ .../java/Simple/EnhancedSwitch.log.txt | 53 +++++++++++++++++++ .../java/Simple/EnhancedSwitch.render.txt | 42 +++++++++++++++ .../uast/test/java/SimpleJavaRenderLogTest.kt | 3 ++ 7 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 uast/uast-tests/java/Simple/EnhancedSwitch.java create mode 100644 uast/uast-tests/java/Simple/EnhancedSwitch.log.txt create mode 100644 uast/uast-tests/java/Simple/EnhancedSwitch.render.txt diff --git a/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt b/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt index 0c9de1ed63f1..2658b5db56cf 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/JavaAbstractUElement.kt @@ -69,7 +69,7 @@ private fun JavaAbstractUElement.unwrapSwitch(uParent: UElement): UElement { is JavaUCodeBlockExpression -> { val codeBlockParent = uParent.uastParent if (codeBlockParent is JavaUSwitchEntryList) { - if (branchHasElement(psi, codeBlockParent.psi) { it is PsiSwitchLabelStatement }) { + if (branchHasElement(psi, codeBlockParent.psi) { it is PsiSwitchLabelStatementBase }) { return codeBlockParent } val psiElement = psi ?: return uParent @@ -81,8 +81,16 @@ private fun JavaAbstractUElement.unwrapSwitch(uParent: UElement): UElement { return uParent } + is JavaUSwitchEntry -> { + val parentSourcePsi = uParent.sourcePsi + if (parentSourcePsi is PsiSwitchLabeledRuleStatement && parentSourcePsi.body?.children?.contains(psi) == true) + return uParent.body + else + return uParent + } + is USwitchExpression -> { - val parentPsi = uParent.psi as PsiSwitchStatement + val parentPsi = uParent.psi as PsiSwitchBlock return if (this === uParent.body || branchHasElement(psi, parentPsi) { it === parentPsi.expression }) uParent else 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 0d1b8d56a1fc..feb5fb477007 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt @@ -251,6 +251,7 @@ internal object JavaConverter { is PsiClassObjectAccessExpression -> expr(build(::JavaUClassLiteralExpression)) is PsiArrayAccessExpression -> expr(build(::JavaUArrayAccessExpression)) is PsiLambdaExpression -> expr(build(::JavaULambdaExpression)) + is PsiSwitchExpression -> expr(build(::JavaUSwitchExpression)) else -> expr(build(::UnknownJavaExpression)) } } @@ -290,10 +291,10 @@ internal object JavaConverter { is PsiSynchronizedStatement -> expr(build(::JavaUSynchronizedExpression)) is PsiTryStatement -> expr(build(::JavaUTryExpression)) is PsiEmptyStatement -> expr { UastEmptyExpression(el.parent?.toUElement()) } - is PsiSwitchLabelStatement -> expr { + is PsiSwitchLabelStatementBase -> expr { when { givenParent is JavaUSwitchEntryList -> givenParent.findUSwitchEntryForLabel(el) - givenParent == null -> PsiTreeUtil.getParentOfType(el, PsiSwitchStatement::class.java)?.let { + givenParent == null -> PsiTreeUtil.getParentOfType(el, PsiSwitchBlock::class.java)?.let { JavaUSwitchExpression(it, null).body.findUSwitchEntryForLabel(el) } else -> null 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 d5c65458df45..d5f751766c5a 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 @@ -15,17 +15,14 @@ */ package org.jetbrains.uast.java -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiStatement -import com.intellij.psi.PsiSwitchLabelStatement -import com.intellij.psi.PsiSwitchStatement +import com.intellij.psi.* import com.intellij.psi.impl.source.tree.ChildRole import org.jetbrains.uast.* import org.jetbrains.uast.java.expressions.JavaUExpressionList import org.jetbrains.uast.java.kinds.JavaSpecialExpressionKinds class JavaUSwitchExpression( - override val psi: PsiSwitchStatement, + override val psi: PsiSwitchBlock, givenParent: UElement? ) : JavaAbstractUExpression(givenParent), USwitchExpression { override val expression: UExpression by lz { JavaConverter.convertOrEmpty(psi.expression, this) } @@ -37,7 +34,7 @@ class JavaUSwitchExpression( } -class JavaUSwitchEntryList(override val psi: PsiSwitchStatement, override val uastParent: JavaUSwitchExpression) : +class JavaUSwitchEntryList(override val psi: PsiSwitchBlock, override val uastParent: JavaUSwitchExpression) : JavaAbstractUExpression(uastParent), UExpressionList { override val kind: UastSpecialExpressionKind @@ -49,10 +46,13 @@ class JavaUSwitchEntryList(override val psi: PsiSwitchStatement, override val ua private val switchEntries: Lazy> = lazy { val statements = psi.body?.statements ?: return@lazy emptyList() - var currentLabels = listOf() + var currentLabels = listOf() var currentBody = listOf() val result = mutableListOf() for (statement in statements) { + if (statement is PsiSwitchLabeledRuleStatement) { + result += JavaUSwitchEntry(listOf(statement), listOfNotNull(statement.body), this) + } if (statement is PsiSwitchLabelStatement) { if (currentBody.isEmpty()) { currentLabels += statement @@ -76,9 +76,13 @@ class JavaUSwitchEntryList(override val psi: PsiSwitchStatement, override val ua override val expressions: List get() = switchEntries.value - fun findUSwitchEntryForLabel(switchLabelStatement: PsiSwitchLabelStatement): JavaUSwitchEntry? { + fun findUSwitchEntryForLabel(switchLabelStatement: PsiSwitchLabelStatementBase): JavaUSwitchEntry? { if (switchEntries.isInitialized()) return switchEntries.value.find { it.labels.contains(switchLabelStatement) } + if (switchLabelStatement is PsiSwitchLabeledRuleStatement) { + return JavaUSwitchEntry(listOf(switchLabelStatement), listOfNotNull(switchLabelStatement.body), this) + } + val bodyStart = switchLabelStatement.nextSiblings.find { it !is PsiSwitchLabelStatement } ?: return null val body = bodyStart.nextSiblings.takeWhile { it !is PsiSwitchLabelStatement }.filterIsInstance().toList() val labels = switchLabelStatement.prevSiblings.takeWhile { it is PsiSwitchLabelStatement }.filterIsInstance().toList() @@ -103,11 +107,11 @@ private val PsiElement.prevSiblings: Sequence get() = generateSequen class JavaUSwitchEntry( - val labels: List, + val labels: List, val statements: List, givenParent: UElement? ) : JavaAbstractUExpression(givenParent), USwitchClauseExpressionWithBody { - override val psi: PsiSwitchLabelStatement = labels.first() + override val psi: PsiSwitchLabelStatementBase = labels.first() override val caseValues: List by lz { labels.mapNotNull { diff --git a/uast/uast-tests/java/Simple/EnhancedSwitch.java b/uast/uast-tests/java/Simple/EnhancedSwitch.java new file mode 100644 index 000000000000..8cd7e6836643 --- /dev/null +++ b/uast/uast-tests/java/Simple/EnhancedSwitch.java @@ -0,0 +1,27 @@ +public class Main { + + private static String getString() { + var str = "abc"; + + final String numericString = + switch (str) { + case "foo" -> "FOO"; + case "bar" -> "BAR"; + case "baz" -> "bAz"; + default -> "default"; + }; + + final String numericString2 = + switch (str) { + case "foo": + break "FOO"; + case "bar": + break "BAR"; + case "baz": + break "bAz"; + default: + break "default"; + }; + return numericString + numericString2; + } +} \ No newline at end of file diff --git a/uast/uast-tests/java/Simple/EnhancedSwitch.log.txt b/uast/uast-tests/java/Simple/EnhancedSwitch.log.txt new file mode 100644 index 000000000000..f2b7dd4a1055 --- /dev/null +++ b/uast/uast-tests/java/Simple/EnhancedSwitch.log.txt @@ -0,0 +1,53 @@ +UFile (package = ) + UClass (name = Main) + UMethod (name = getString) + UBlockExpression + UDeclarationsExpression + ULocalVariable (name = str) + ULiteralExpression (value = "abc") + UDeclarationsExpression + ULocalVariable (name = numericString) + USwitchExpression + USimpleNameReferenceExpression (identifier = str) + UExpressionList (switch) + USwitchClauseExpressionWithBody + ULiteralExpression (value = "foo") + UExpressionList (switch_entry) + ULiteralExpression (value = "FOO") + USwitchClauseExpressionWithBody + ULiteralExpression (value = "bar") + UExpressionList (switch_entry) + ULiteralExpression (value = "BAR") + USwitchClauseExpressionWithBody + ULiteralExpression (value = "baz") + UExpressionList (switch_entry) + ULiteralExpression (value = "bAz") + USwitchClauseExpressionWithBody + UDefaultCaseExpression + UExpressionList (switch_entry) + ULiteralExpression (value = "default") + UDeclarationsExpression + ULocalVariable (name = numericString2) + USwitchExpression + USimpleNameReferenceExpression (identifier = str) + UExpressionList (switch) + USwitchClauseExpressionWithBody + ULiteralExpression (value = "foo") + UExpressionList (switch_entry) + UBreakExpression (label = null) + USwitchClauseExpressionWithBody + ULiteralExpression (value = "bar") + UExpressionList (switch_entry) + UBreakExpression (label = null) + USwitchClauseExpressionWithBody + ULiteralExpression (value = "baz") + UExpressionList (switch_entry) + UBreakExpression (label = null) + USwitchClauseExpressionWithBody + UDefaultCaseExpression + UExpressionList (switch_entry) + UBreakExpression (label = null) + UReturnExpression + UBinaryExpression (operator = +) + USimpleNameReferenceExpression (identifier = numericString) + USimpleNameReferenceExpression (identifier = numericString2) diff --git a/uast/uast-tests/java/Simple/EnhancedSwitch.render.txt b/uast/uast-tests/java/Simple/EnhancedSwitch.render.txt new file mode 100644 index 000000000000..dd5b9739b308 --- /dev/null +++ b/uast/uast-tests/java/Simple/EnhancedSwitch.render.txt @@ -0,0 +1,42 @@ +public class Main { + private static fun getString() : java.lang.String { + var str: var = "abc" + final var numericString: java.lang.String = switch (str) + "foo" -> { + "FOO" + } + + "bar" -> { + "BAR" + } + + "baz" -> { + "bAz" + } + + else -> { + "default" + } + + + final var numericString2: java.lang.String = switch (str) + "foo" -> { + break + } + + "bar" -> { + break + } + + "baz" -> { + break + } + + else -> { + break + } + + + return numericString + numericString2 + } +} 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 db51daf841d4..68a04405c1d9 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 @@ -24,6 +24,9 @@ class SimpleJavaRenderLogTest : AbstractJavaRenderLogTest() { @Test fun testEnumSwitch() = doTest("Simple/EnumSwitch.java") + @Test + fun testEnhancedSwitch() = doTest("Simple/EnhancedSwitch.java") + @Test fun testLocalClass() = doTest("Simple/LocalClass.java")