Skip to content

Commit

Permalink
[StatementSwitchToExpressionSwitch] Bugfix scenario where local var
Browse files Browse the repository at this point in the history
…s take on intersection types, which are not supported for hoisting

PiperOrigin-RevId: 731022030
  • Loading branch information
markhbrady authored and Error Prone Team committed Feb 28, 2025
1 parent aae4d8d commit ba613c7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.IntersectionType;

/** Checks for statement switches that can be expressed as an equivalent expression switch. */
@BugPattern(
Expand Down Expand Up @@ -375,8 +376,14 @@ && isSwitchExhaustiveWithoutDefault(
&& exhaustive;
boolean canConvertDirectlyToExpressionSwitch =
allCasesHaveDefiniteControlFlow
// Hoisting currently not supported for arrays due to restrictions on using assignment
// expressions to initialize them
&& symbolsToHoist.keySet().stream()
.noneMatch(symbol -> state.getTypes().isArray(symbol.type));
.noneMatch(symbol -> state.getTypes().isArray(symbol.type))
// Hoisting currently not supported for intersection types because the type is not
// denotable as an explicit type (see JLS 21 § 14.4.1.)
&& symbolsToHoist.keySet().stream()
.noneMatch(symbol -> symbol.type instanceof IntersectionType);

List<StatementTree> precedingStatements = getPrecedingStatementsInBlock(switchTree, state);
Optional<ExpressionTree> assignmentTarget =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5760,6 +5760,99 @@ public int[] foo() {
.doTest();
}

@Test
public void directConversion_hoistIntersectionType_noError() {
// The type of foo is an intersection type, which is not supported for hoisting.
helper
.addSourceLines(
"Test.java",
"""
class Test {
int[] x;
public Test(int foo) {
x = null;
}
public int[] foo() {
int z = 1;
switch (z) {
case 1:
var foo = (CharSequence & Comparable<String>) "hello";
break;
case 2:
foo = "there";
}
return x;
}
}
""")
.setArgs("-XepOpt:StatementSwitchToExpressionSwitch:EnableDirectConversion")
.doTest();
}

@Test
public void directConversion_typeParameterWithIntersection_error() {
// Type parameters containing type intersections are supported for hoisting.
refactoringHelper
.addInputLines(
"Test.java",
"""
class Test {
int[] x;
public Test(int foo) {
x = null;
}
public static <T extends CharSequence & Comparable<String>> int[] foo() {
int z = 1;
switch (z) {
case 1:
T foo = null;
break;
case 2:
System.out.println("Somehow, z was 2.");
foo = null;
}
return new int[0];
}
}
""")
.addOutputLines(
"Test.java",
"""
class Test {
int[] x;
public Test(int foo) {
x = null;
}
public static <T extends CharSequence & Comparable<String>> int[] foo() {
int z = 1;
T foo;
switch(z) {
case 1 -> {
foo = null;
}
case 2 -> {
System.out.println("Somehow, z was 2.");
foo = null;
}
}
return new int[0];
}
}
""")
.setArgs("-XepOpt:StatementSwitchToExpressionSwitch:EnableDirectConversion")
.setFixChooser(StatementSwitchToExpressionSwitchTest::assertOneFixAndChoose)
.doTest(BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH);
}

@Test
public void directConversion_lexicalScopeOverlap3_error() {
// Switch statement is in a labeled statement. The checker must surround the switch statement
Expand Down

0 comments on commit ba613c7

Please sign in to comment.