[uast] UBreakWithValueExpression for evaluating Java 12 "enhanced" switch (IDEA-202555)

This commit is contained in:
Nicolay Mitropolsky
2018-12-19 17:04:15 +03:00
parent 3b6205afca
commit f8aed5ba57
16 changed files with 514 additions and 34 deletions
@@ -113,7 +113,12 @@ class TreeBasedEvaluator(
override fun visitBreakExpression(node: UBreakExpression, data: UEvaluationState): UEvaluationInfo {
storeState(node, data)
return UNothingValue(node) to data storeResultFor node
return when (node) {
is UBreakWithValueExpression ->
node.valueExpression?.accept(chain, data)?.let { UBreakResult(it.value, node) } ?: UUndeterminedValue
else ->
UNothingValue(node)
} to data storeResultFor node
}
override fun visitContinueExpression(node: UContinueExpression, data: UEvaluationState): UEvaluationInfo {
@@ -523,9 +528,9 @@ class TreeBasedEvaluator(
if (!clauseInfo.reachable) break
}
val clauseValue = clauseInfo.value
if (clauseValue is UNothingValue && clauseValue.containingLoopOrSwitch == node) {
if (exitingNode(clauseValue) == node) {
// break from switch
resultInfo = resultInfo?.merge(clauseInfo) ?: clauseInfo
resultInfo = resultInfo merge getBreakResult(clauseInfo)
if (caseCondition == UBooleanConstant.True) break@clausesLoop
clauseInfo = subjectInfo
fallThroughCondition = UBooleanConstant.False
@@ -546,6 +551,32 @@ class TreeBasedEvaluator(
return resultInfo storeResultFor node
}
private fun exitingNode(uValue: UValue): UExpression? {
when (uValue) {
is UNothingValue -> return uValue.containingLoopOrSwitch
is UPhiValue -> {
for (value in uValue.values) if (value is UBreakResult) return value.containingLoopOrSwitch
for (value in uValue.values) if (value is UNothingValue) value.containingLoopOrSwitch?.let { return it }
return null
}
else -> return null
}
}
private fun getBreakResult(clauseInfo: UEvaluationInfo): UEvaluationInfo {
val clauseValue = clauseInfo.value
return when (clauseValue) {
is UBreakResult -> clauseValue.value to clauseInfo.state
is UPhiValue -> UPhiValue.create(clauseValue.values.map {
when (it) {
is UBreakResult -> it.value
else -> it
}
}) to clauseInfo.state
else -> clauseInfo
}
}
private fun evaluateLoop(
loop: ULoopExpression,
inputState: UEvaluationState,
@@ -34,4 +34,9 @@ data class UEvaluationInfo(val value: UValue, val state: UEvaluationState) {
get() = value.reachable
}
infix fun UEvaluationInfo?.merge(otherInfo: UEvaluationInfo?): UEvaluationInfo? =
if (this != null)
if (otherInfo != null) this.merge(otherInfo) else this
else otherInfo
infix fun UValue.to(state: UEvaluationState): UEvaluationInfo = UEvaluationInfo(this, state)
@@ -38,4 +38,25 @@ interface UBreakExpression : UJumpExpression {
override fun asLogString(): String = log("label = $label")
override fun asRenderString(): String = label?.let { "break@$it" } ?: "break"
}
interface UBreakWithValueExpression : UBreakExpression {
val valueExpression: UExpression?
override fun accept(visitor: UastVisitor) {
if (visitor.visitBreakExpression(this)) return
annotations.acceptList(visitor)
valueExpression?.accept(visitor)
visitor.afterVisitBreakExpression(this)
}
override fun asLogString(): String = log("label = $label, hasValue = ${valueExpression != null}")
override fun asRenderString(): String = buildString {
append("break")
label?.let { append("@$it") }
valueExpression?.let { append(" ${it.asRenderString()}") }
}
}
@@ -18,7 +18,7 @@ package org.jetbrains.uast.values
import org.jetbrains.uast.*
// Something that never can be reached / created
internal class UNothingValue private constructor(
internal open class UNothingValue private constructor(
val containingLoopOrSwitch: UExpression?,
val kind: JumpKind
) : UValueBase() {
@@ -36,6 +36,7 @@ internal class UNothingValue private constructor(
override val reachable = false
override fun merge(other: UValue) = when (other) {
is UBreakResult -> other
is UNothingValue -> {
val mergedLoopOrSwitch =
if (containingLoopOrSwitch == other.containingLoopOrSwitch) containingLoopOrSwitch
@@ -43,7 +44,7 @@ internal class UNothingValue private constructor(
val mergedKind = if (mergedLoopOrSwitch == null || kind != other.kind) JumpKind.OTHER else kind
UNothingValue(mergedLoopOrSwitch, mergedKind)
}
else -> super.merge(other)
else -> other
}
override fun toString() = "Nothing" + when (kind) {
@@ -77,3 +78,13 @@ internal class UNothingValue private constructor(
}
}
}
internal class UBreakResult(val value: UValue, jump: UBreakWithValueExpression) : UNothingValue(jump) {
override fun toString(): String = "UBreakResult($value)"
override fun merge(other: UValue): UValue = when (other) {
is UBreakResult -> UPhiValue.create(this, other)
is UNothingValue -> this
else -> other.merge(this)
}
}
@@ -11,6 +11,9 @@ class UPhiValue private constructor(val values: Set<UValue>) : UValueBase() {
override fun toString(): String = values.joinToString(prefix = "Phi(", postfix = ")", separator = ", ")
override val reachable: Boolean
get() = values.any { it.reachable }
companion object {
private const val PHI_LIMIT = 4
@@ -66,7 +66,6 @@ abstract class JavaAbstractUElement(givenParent: UElement?) : JavaUElementWithCo
private fun JavaAbstractUElement.unwrapSwitch(uParent: UElement): UElement {
when (uParent) {
is UBreakExpression -> return uParent.uastParent ?: uParent
is UBlockExpression -> {
val codeBlockParent = uParent.uastParent
when (codeBlockParent) {
@@ -92,8 +91,12 @@ private fun JavaAbstractUElement.unwrapSwitch(uParent: UElement): UElement {
is JavaUSwitchEntry -> {
val parentSourcePsi = uParent.sourcePsi
if (parentSourcePsi is PsiSwitchLabeledRuleStatement && parentSourcePsi.body?.children?.contains(psi) == true)
return uParent.body
if (parentSourcePsi is PsiSwitchLabeledRuleStatement && parentSourcePsi.body?.children?.contains(psi) == true) {
val psi = psi
return if (psi is PsiExpression && uParent.body.expressions.size == 1)
DummyUBreakExpression(psi, uParent.body)
else uParent.body
}
else
return uParent
}
@@ -288,7 +288,9 @@ internal object JavaConverter {
is PsiDoWhileStatement -> expr<UDoWhileExpression>(build(::JavaUDoWhileExpression))
is PsiForStatement -> expr<UForExpression>(build(::JavaUForExpression))
is PsiForeachStatement -> expr<UForEachExpression>(build(::JavaUForEachExpression))
is PsiBreakStatement -> expr<UBreakExpression>(build(::JavaUBreakExpression))
is PsiBreakStatement -> expr<UBreakExpression> {
el.valueExpression?.let { JavaUBreakWithValueExpression(el, it, givenParent) } ?: JavaUBreakExpression(el, givenParent)
}
is PsiContinueStatement -> expr<UContinueExpression>(build(::JavaUContinueExpression))
is PsiReturnStatement -> expr<UReturnExpression>(build(::JavaUReturnExpression))
is PsiAssertStatement -> expr<UCallExpression>(build(::JavaUAssertExpression))
@@ -54,9 +54,9 @@ class JavaUSwitchEntryList(override val psi: PsiSwitchBlock, override val uastPa
val body = statement.body
result += when (body) {
is PsiBlockStatement ->
JavaUSwitchEntry(listOf(statement), body.codeBlock.statements.toList(), this)
JavaUSwitchEntry(listOf(statement), body.codeBlock.statements.toList(), this, false)
else ->
JavaUSwitchEntry(listOf(statement), listOfNotNull(body), this)
JavaUSwitchEntry(listOf(statement), listOfNotNull(body), this, true)
}
}
@@ -87,7 +87,7 @@ class JavaUSwitchEntryList(override val psi: PsiSwitchBlock, override val uastPa
if (switchEntries.isInitialized()) return switchEntries.value.find { it.labels.contains(switchLabelStatement) }
if (switchLabelStatement is PsiSwitchLabeledRuleStatement) {
return JavaUSwitchEntry(listOf(switchLabelStatement), listOfNotNull(switchLabelStatement.body), this)
return JavaUSwitchEntry(listOf(switchLabelStatement), listOfNotNull(switchLabelStatement.body), this, true)
}
val bodyStart = switchLabelStatement.nextSiblings.find { it !is PsiSwitchLabelStatement } ?: return null
@@ -116,7 +116,8 @@ private val PsiElement.prevSiblings: Sequence<PsiElement> get() = generateSequen
class JavaUSwitchEntry(
val labels: List<PsiSwitchLabelStatementBase>,
val statements: List<PsiStatement>,
givenParent: UElement?
givenParent: UElement?,
private val addDummyBreak: Boolean = false
) : JavaAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
override val psi: PsiSwitchLabelStatementBase = labels.first()
@@ -134,8 +135,21 @@ class JavaUSwitchEntry(
override val body: UExpressionList by lz {
object : JavaUExpressionList(psi, JavaSpecialExpressionKinds.SWITCH_ENTRY, this) {
override val expressions: List<UExpression> =
this@JavaUSwitchEntry.statements.map { JavaConverter.convertOrEmpty(it, this) }
override val expressions: List<UExpression>
init {
val expressions = ArrayList<UExpression>(this@JavaUSwitchEntry.statements.size)
for (statement in this@JavaUSwitchEntry.statements) {
expressions.add(JavaConverter.convertOrEmpty(statement, this))
}
if (addDummyBreak) {
val lastValueExpressionPsi = expressions.lastOrNull()?.sourcePsi as? PsiExpression
if (lastValueExpressionPsi != null)
expressions[expressions.size - 1] = DummyUBreakExpression(lastValueExpressionPsi, this)
}
this.expressions = expressions
}
override fun asRenderString() = buildString {
appendln("{")
@@ -144,6 +158,33 @@ class JavaUSwitchEntry(
}
}
}
}
internal class DummyUBreakExpression(val valueExpressionPsi: PsiExpression,
override val uastParent: UElement?) : UBreakWithValueExpression {
override val javaPsi: PsiElement? = null
override val sourcePsi: PsiElement? = null
override val psi: PsiElement?
get() = null
override val label: String?
get() = null
override val annotations: List<UAnnotation>
get() = emptyList()
override val valueExpression: UExpression? by lazy { JavaConverter.convertExpression(valueExpressionPsi, this) }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as DummyUBreakExpression
return valueExpressionPsi == other.valueExpressionPsi
}
override fun hashCode(): Int = valueExpressionPsi.hashCode()
}
class JavaUDefaultCaseExpression(override val psi: PsiElement?, givenParent: UElement?)
@@ -17,8 +17,11 @@
package org.jetbrains.uast.java
import com.intellij.psi.PsiBreakStatement
import com.intellij.psi.PsiExpression
import org.jetbrains.uast.UBreakExpression
import org.jetbrains.uast.UBreakWithValueExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
class JavaUBreakExpression(
override val psi: PsiBreakStatement,
@@ -26,4 +29,16 @@ class JavaUBreakExpression(
) : JavaAbstractUExpression(givenParent), UBreakExpression {
override val label: String?
get() = psi.labelIdentifier?.text
}
class JavaUBreakWithValueExpression(
override val psi: PsiBreakStatement,
val psiExpression: PsiExpression,
givenParent: UElement?
) : JavaAbstractUExpression(givenParent), UBreakWithValueExpression {
override val valueExpression: UExpression? by lazy {
JavaConverter.convertExpression(psiExpression, this)
}
override val label: String?
get() = psi.labelIdentifier?.text
}
@@ -1,7 +1,7 @@
public class Main {
private static String getString() {
var str = "abc";
var str = "baz";
final String numericString =
switch (str) {
@@ -4,7 +4,7 @@ UFile (package = )
UBlockExpression
UDeclarationsExpression
ULocalVariable (name = str)
ULiteralExpression (value = "abc")
ULiteralExpression (value = "baz")
UDeclarationsExpression
ULocalVariable (name = numericString)
USwitchExpression
@@ -20,20 +20,24 @@ UFile (package = )
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
UIdentifier (Identifier (println))
ULiteralExpression (value = "here")
UBreakExpression (label = null)
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "FOO")
USwitchClauseExpressionWithBody
ULiteralExpression (value = "bar")
ULiteralExpression (value = "beer")
UExpressionList (switch_entry)
ULiteralExpression (value = "BAR")
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "BAR")
USwitchClauseExpressionWithBody
ULiteralExpression (value = "baz")
UExpressionList (switch_entry)
ULiteralExpression (value = "bAz")
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "bAz")
USwitchClauseExpressionWithBody
UDefaultCaseExpression
UExpressionList (switch_entry)
ULiteralExpression (value = "default")
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "default")
UDeclarationsExpression
ULocalVariable (name = numericString2)
USwitchExpression
@@ -42,11 +46,13 @@ UFile (package = )
USwitchClauseExpressionWithBody
ULiteralExpression (value = "foo")
UExpressionList (switch_entry)
UBreakExpression (label = null)
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "FOO")
USwitchClauseExpressionWithBody
ULiteralExpression (value = "bar")
UExpressionList (switch_entry)
UBreakExpression (label = null)
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "BAR")
USwitchClauseExpressionWithBody
ULiteralExpression (value = "baz")
ULiteralExpression (value = "zub")
@@ -58,11 +64,13 @@ UFile (package = )
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
UIdentifier (Identifier (println))
ULiteralExpression (value = "here")
UBreakExpression (label = null)
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "bAz")
USwitchClauseExpressionWithBody
UDefaultCaseExpression
UExpressionList (switch_entry)
UBreakExpression (label = null)
UBreakWithValueExpression (label = null, hasValue = true)
ULiteralExpression (value = "default")
UReturnExpression
UBinaryExpression (operator = +)
USimpleNameReferenceExpression (identifier = numericString)
@@ -1,41 +1,41 @@
public class Main {
private static fun getString() : java.lang.String {
var str: var = "abc"
var str: var = "baz"
final var numericString: java.lang.String = switch (str)
"foo" -> {
System.out.println("here")
break
break "FOO"
}
"bar", "beer" -> {
"BAR"
break "BAR"
}
"baz" -> {
"bAz"
break "bAz"
}
else -> {
"default"
break "default"
}
final var numericString2: java.lang.String = switch (str)
"foo" -> {
break
break "FOO"
}
"bar" -> {
break
break "BAR"
}
"baz", "zub" -> {
System.out.println("here")
break
break "bAz"
}
else -> {
break
break "default"
}
@@ -0,0 +1,77 @@
UFile (package = ) [public class Main {...]
UClass (name = Main) [public class Main {...}]
UMethod (name = getString) [private static fun getString() : java.lang.String {...}]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var str: var = "baz"] = Undetermined
ULocalVariable (name = str) [var str: var = "baz"]
ULiteralExpression (value = "baz") ["baz"] = "baz"
UDeclarationsExpression [final var numericString: java.lang.String = switch (str) ...] = Undetermined
ULocalVariable (name = numericString) [final var numericString: java.lang.String = switch (str) ...]
USwitchExpression [switch (str) ...] = "bAz"
USimpleNameReferenceExpression (identifier = str) [str] = (var str = "baz")
UExpressionList (switch) [ "foo" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
UExpressionList (switch_entry) [{...] = Undetermined
UQualifiedReferenceExpression [System.out.println("here")] = external println("here")("here")
UQualifiedReferenceExpression [System.out] = Undetermined
USimpleNameReferenceExpression (identifier = System) [System] = external System()
USimpleNameReferenceExpression (identifier = out) [out] = Undetermined
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) [println("here")] = external println("here")("here")
UIdentifier (Identifier (println)) [UIdentifier (Identifier (println))]
ULiteralExpression (value = "here") ["here"] = "here"
UBreakWithValueExpression (label = null, hasValue = true) [break "FOO"] = UBreakResult("FOO")
ULiteralExpression (value = "FOO") ["FOO"] = "FOO"
USwitchClauseExpressionWithBody ["bar", "beer" -> {...] = Undetermined
ULiteralExpression (value = "bar") ["bar"] = "bar"
ULiteralExpression (value = "beer") ["beer"] = "beer"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "BAR"] = UBreakResult("BAR")
ULiteralExpression (value = "BAR") ["BAR"] = "BAR"
USwitchClauseExpressionWithBody ["baz" -> {...] = Undetermined
ULiteralExpression (value = "baz") ["baz"] = "baz"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "bAz"] = UBreakResult("bAz")
ULiteralExpression (value = "bAz") ["bAz"] = "bAz"
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "default"] = UBreakResult("default")
ULiteralExpression (value = "default") ["default"] = "default"
UDeclarationsExpression [final var numericString2: java.lang.String = switch (str) ...] = Undetermined
ULocalVariable (name = numericString2) [final var numericString2: java.lang.String = switch (str) ...]
USwitchExpression [switch (str) ...] = "bAz"
USimpleNameReferenceExpression (identifier = str) [str] = (var str = "baz")
UExpressionList (switch) [ "foo" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "FOO"] = UBreakResult("FOO")
ULiteralExpression (value = "FOO") ["FOO"] = "FOO"
USwitchClauseExpressionWithBody ["bar" -> {...] = Undetermined
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "BAR"] = UBreakResult("BAR")
ULiteralExpression (value = "BAR") ["BAR"] = "BAR"
USwitchClauseExpressionWithBody ["baz", "zub" -> {...] = Undetermined
ULiteralExpression (value = "baz") ["baz"] = "baz"
ULiteralExpression (value = "zub") ["zub"] = "zub"
UExpressionList (switch_entry) [{...] = Undetermined
UQualifiedReferenceExpression [System.out.println("here")] = external println("here")("here")
UQualifiedReferenceExpression [System.out] = Undetermined
USimpleNameReferenceExpression (identifier = System) [System] = external System()
USimpleNameReferenceExpression (identifier = out) [out] = Undetermined
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) [println("here")] = external println("here")("here")
UIdentifier (Identifier (println)) [UIdentifier (Identifier (println))]
ULiteralExpression (value = "here") ["here"] = "here"
UBreakWithValueExpression (label = null, hasValue = true) [break "bAz"] = UBreakResult("bAz")
ULiteralExpression (value = "bAz") ["bAz"] = "bAz"
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "default"] = UBreakResult("default")
ULiteralExpression (value = "default") ["default"] = "default"
UReturnExpression [return numericString + numericString2] = Nothing
UBinaryExpression (operator = +) [numericString + numericString2] = "bAzbAz" (depending on: (var numericString = "bAz"), (var numericString2 = "bAz"))
USimpleNameReferenceExpression (identifier = numericString) [numericString] = (var numericString = "bAz")
USimpleNameReferenceExpression (identifier = numericString2) [numericString2] = (var numericString2 = "bAz")
@@ -0,0 +1,85 @@
public class Main {
private static String getOneOrTwoString(String unknown) {
final String switchResult =
switch (unknown) {
case "foo", "bar" -> "foobar";
default -> "default";
};
return switchResult;
}
private static String getOneOrThrow(String unknown) {
final String switchResult =
switch (unknown) {
case "foo", "bar" -> "foobar";
default -> throw new IllegalArgumentException();
};
return switchResult;
}
private static String getThrowOrOne(String unknown) {
final String switchResult =
switch (unknown) {
case "foo", "bar" -> throw new IllegalArgumentException();
default -> "foobar";
};
return switchResult;
}
private static String getUnknownString(String unknown) {
final String switchResult =
switch (unknown) {
case "foo", "bar" -> "foobar" + unknown;
default -> "default" + unknown;
};
return switchResult;
}
private static int getOneInsideOrThrow(String unknown) {
String known = "abc";
final int switchResult =
switch (known) {
case "foo":
case "bar":
break 0;
default:
if (unknown.length() > 0) {
break 12;
} else
throw new IllegalArgumentException();
};
return switchResult;
}
private static int getThrowOrOneInside(String unknown) {
String known = "abc";
final int switchResult =
switch (known) {
case "foo":
case "bar":
break 0;
default:
if (unknown.length() <= 0) {
throw new IllegalArgumentException();
}
else if (unknown.equals("true")) {
break 12;
}
else {
break 18;
}
};
return switchResult;
}
}
@@ -0,0 +1,172 @@
UFile (package = ) [public class Main {...]
UClass (name = Main) [public class Main {...}]
UMethod (name = getOneOrTwoString) [private static fun getOneOrTwoString(unknown: java.lang.String) : java.lang.String {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [final var switchResult: java.lang.String = switch (unknown) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: java.lang.String = switch (unknown) ...]
USwitchExpression [switch (unknown) ...] = Phi("foobar", "default")
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "foobar"] = UBreakResult("foobar")
ULiteralExpression (value = "foobar") ["foobar"] = "foobar"
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "default"] = UBreakResult("default")
ULiteralExpression (value = "default") ["default"] = "default"
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = Phi("foobar", "default"))
UMethod (name = getOneOrThrow) [private static fun getOneOrThrow(unknown: java.lang.String) : java.lang.String {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [final var switchResult: java.lang.String = switch (unknown) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: java.lang.String = switch (unknown) ...]
USwitchExpression [switch (unknown) ...] = "foobar"
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "foobar"] = UBreakResult("foobar")
ULiteralExpression (value = "foobar") ["foobar"] = "foobar"
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UThrowExpression [throw IllegalArgumentException()] = Nothing
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [IllegalArgumentException()] = external IllegalArgumentException()()
USimpleNameReferenceExpression (identifier = IllegalArgumentException) [IllegalArgumentException] = external IllegalArgumentException()
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = "foobar")
UMethod (name = getThrowOrOne) [private static fun getThrowOrOne(unknown: java.lang.String) : java.lang.String {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [final var switchResult: java.lang.String = switch (unknown) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: java.lang.String = switch (unknown) ...]
USwitchExpression [switch (unknown) ...] = "foobar"
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UThrowExpression [throw IllegalArgumentException()] = Nothing
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [IllegalArgumentException()] = external IllegalArgumentException()()
USimpleNameReferenceExpression (identifier = IllegalArgumentException) [IllegalArgumentException] = external IllegalArgumentException()
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "foobar"] = UBreakResult("foobar")
ULiteralExpression (value = "foobar") ["foobar"] = "foobar"
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = "foobar")
UMethod (name = getUnknownString) [private static fun getUnknownString(unknown: java.lang.String) : java.lang.String {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [final var switchResult: java.lang.String = switch (unknown) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: java.lang.String = switch (unknown) ...]
USwitchExpression [switch (unknown) ...] = Undetermined
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "foobar" + unknown] = UBreakResult(Undetermined)
UBinaryExpression (operator = +) ["foobar" + unknown] = Undetermined
ULiteralExpression (value = "foobar") ["foobar"] = "foobar"
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break "default" + unknown] = UBreakResult(Undetermined)
UBinaryExpression (operator = +) ["default" + unknown] = Undetermined
ULiteralExpression (value = "default") ["default"] = "default"
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = Undetermined)
UMethod (name = getOneInsideOrThrow) [private static fun getOneInsideOrThrow(unknown: java.lang.String) : int {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var known: java.lang.String = "abc"] = Undetermined
ULocalVariable (name = known) [var known: java.lang.String = "abc"]
ULiteralExpression (value = "abc") ["abc"] = "abc"
UDeclarationsExpression [final var switchResult: int = switch (known) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: int = switch (known) ...]
USwitchExpression [switch (known) ...] = 12
USimpleNameReferenceExpression (identifier = known) [known] = (var known = "abc")
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break 0] = UBreakResult(0)
ULiteralExpression (value = 0) [0] = 0
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UIfExpression [if (unknown.length() > 0) {...}else throw IllegalArgumentException()] = UBreakResult(12)
UBinaryExpression (operator = >) [unknown.length() > 0] = Undetermined
UQualifiedReferenceExpression [unknown.length()] = external length()()
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [length()] = external length()()
UIdentifier (Identifier (length)) [UIdentifier (Identifier (length))]
ULiteralExpression (value = 0) [0] = 0
UBlockExpression [{...}] = UBreakResult(12)
UBreakWithValueExpression (label = null, hasValue = true) [break 12] = UBreakResult(12)
ULiteralExpression (value = 12) [12] = 12
UThrowExpression [throw IllegalArgumentException()] = Nothing
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [IllegalArgumentException()] = external IllegalArgumentException()()
USimpleNameReferenceExpression (identifier = IllegalArgumentException) [IllegalArgumentException] = external IllegalArgumentException()
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = 12)
UMethod (name = getThrowOrOneInside) [private static fun getThrowOrOneInside(unknown: java.lang.String) : int {...}]
UParameter (name = unknown) [var unknown: java.lang.String]
UBlockExpression [{...}] = Nothing
UDeclarationsExpression [var known: java.lang.String = "abc"] = Undetermined
ULocalVariable (name = known) [var known: java.lang.String = "abc"]
ULiteralExpression (value = "abc") ["abc"] = "abc"
UDeclarationsExpression [final var switchResult: int = switch (known) ...] = Undetermined
ULocalVariable (name = switchResult) [final var switchResult: int = switch (known) ...]
USwitchExpression [switch (known) ...] = Phi(12, 18)
USimpleNameReferenceExpression (identifier = known) [known] = (var known = "abc")
UExpressionList (switch) [ "foo", "bar" -> {... ] = Undetermined
USwitchClauseExpressionWithBody ["foo", "bar" -> {...] = Undetermined
ULiteralExpression (value = "foo") ["foo"] = "foo"
ULiteralExpression (value = "bar") ["bar"] = "bar"
UExpressionList (switch_entry) [{...] = Undetermined
UBreakWithValueExpression (label = null, hasValue = true) [break 0] = UBreakResult(0)
ULiteralExpression (value = 0) [0] = 0
USwitchClauseExpressionWithBody [else -> {...] = Undetermined
UDefaultCaseExpression [else] = Undetermined
UExpressionList (switch_entry) [{...] = Undetermined
UIfExpression [if (unknown.length() <= 0) {...}] = Phi(UBreakResult(12), UBreakResult(18))
UBinaryExpression (operator = <=) [unknown.length() <= 0] = Undetermined
UQualifiedReferenceExpression [unknown.length()] = external length()()
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [length()] = external length()()
UIdentifier (Identifier (length)) [UIdentifier (Identifier (length))]
ULiteralExpression (value = 0) [0] = 0
UBlockExpression [{...}] = Nothing
UThrowExpression [throw IllegalArgumentException()] = Nothing
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [IllegalArgumentException()] = external IllegalArgumentException()()
USimpleNameReferenceExpression (identifier = IllegalArgumentException) [IllegalArgumentException] = external IllegalArgumentException()
UIfExpression [if (unknown.equals("true")) {...}] = Phi(UBreakResult(12), UBreakResult(18))
UQualifiedReferenceExpression [unknown.equals("true")] = external equals("true")("true")
USimpleNameReferenceExpression (identifier = unknown) [unknown] = Undetermined
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) [equals("true")] = external equals("true")("true")
UIdentifier (Identifier (equals)) [UIdentifier (Identifier (equals))]
ULiteralExpression (value = "true") ["true"] = "true"
UBlockExpression [{...}] = UBreakResult(12)
UBreakWithValueExpression (label = null, hasValue = true) [break 12] = UBreakResult(12)
ULiteralExpression (value = 12) [12] = 12
UBlockExpression [{...}] = UBreakResult(18)
UBreakWithValueExpression (label = null, hasValue = true) [break 18] = UBreakResult(18)
ULiteralExpression (value = 18) [18] = 18
UReturnExpression [return switchResult] = Nothing
USimpleNameReferenceExpression (identifier = switchResult) [switchResult] = (var switchResult = Phi(12, 18))
@@ -81,6 +81,12 @@ class JavaValuesTest : AbstractJavaValuesTest() {
@Test
fun testEnumSwitch() = doTest("Simple/EnumSwitch.java")
@Test
fun testEnhancedSwitch() = doTest("Simple/EnhancedSwitch.java")
@Test
fun testEnhancedSwitchComplexEvaluations() = doTest("Simple/EnhancedSwitchComplexEvaluations.java")
@Test
fun testEnumSwitchConditionalBreak() = doTest("Simple/EnumSwitchConditionalBreak.java")