[uast-java] Support for converting Java 12 "enhanced" switch expressions (IDEA-202555)

This commit is contained in:
Nicolay Mitropolsky
2018-12-03 10:46:56 +03:00
parent 49061a9324
commit 1e9963ae7d
7 changed files with 152 additions and 14 deletions
@@ -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
@@ -251,6 +251,7 @@ internal object JavaConverter {
is PsiClassObjectAccessExpression -> expr<UClassLiteralExpression>(build(::JavaUClassLiteralExpression))
is PsiArrayAccessExpression -> expr<UArrayAccessExpression>(build(::JavaUArrayAccessExpression))
is PsiLambdaExpression -> expr<ULambdaExpression>(build(::JavaULambdaExpression))
is PsiSwitchExpression -> expr<USwitchExpression>(build(::JavaUSwitchExpression))
else -> expr<UExpression>(build(::UnknownJavaExpression))
}
}
@@ -290,10 +291,10 @@ internal object JavaConverter {
is PsiSynchronizedStatement -> expr<UBlockExpression>(build(::JavaUSynchronizedExpression))
is PsiTryStatement -> expr<UTryExpression>(build(::JavaUTryExpression))
is PsiEmptyStatement -> expr<UExpression> { UastEmptyExpression(el.parent?.toUElement()) }
is PsiSwitchLabelStatement -> expr<UExpression> {
is PsiSwitchLabelStatementBase -> expr<UExpression> {
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
@@ -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<List<JavaUSwitchEntry>> = lazy {
val statements = psi.body?.statements ?: return@lazy emptyList<JavaUSwitchEntry>()
var currentLabels = listOf<PsiSwitchLabelStatement>()
var currentLabels = listOf<PsiSwitchLabelStatementBase>()
var currentBody = listOf<PsiStatement>()
val result = mutableListOf<JavaUSwitchEntry>()
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<JavaUSwitchEntry> 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<PsiStatement>().toList()
val labels = switchLabelStatement.prevSiblings.takeWhile { it is PsiSwitchLabelStatement }.filterIsInstance<PsiSwitchLabelStatement>().toList()
@@ -103,11 +107,11 @@ private val PsiElement.prevSiblings: Sequence<PsiElement> get() = generateSequen
class JavaUSwitchEntry(
val labels: List<PsiSwitchLabelStatement>,
val labels: List<PsiSwitchLabelStatementBase>,
val statements: List<PsiStatement>,
givenParent: UElement?
) : JavaAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
override val psi: PsiSwitchLabelStatement = labels.first()
override val psi: PsiSwitchLabelStatementBase = labels.first()
override val caseValues: List<UExpression> by lz {
labels.mapNotNull {
@@ -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;
}
}
@@ -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)
@@ -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
}
}
@@ -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")