Skip to content

Commit 0bc418e

Browse files
cushongoogle-java-format Team
authored andcommitted
Update handling of pattern matching in switch
for AST changes in Java 17, in particular the addition of CaseTree#getLabels, which returns a single `DefaultCaseLabelTree` to represent the default case. #683 #684 PiperOrigin-RevId: 411074295
1 parent 58978e6 commit 0bc418e

File tree

6 files changed

+85
-36
lines changed

6 files changed

+85
-36
lines changed

core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.google.googlejavaformat.java.java14;
1616

1717
import static com.google.common.collect.ImmutableList.toImmutableList;
18+
import static com.google.common.collect.Iterables.getOnlyElement;
1819

1920
import com.google.common.base.Verify;
2021
import com.google.common.collect.ImmutableList;
@@ -27,7 +28,6 @@
2728
import com.sun.source.tree.CaseTree;
2829
import com.sun.source.tree.ClassTree;
2930
import com.sun.source.tree.CompilationUnitTree;
30-
import com.sun.source.tree.ExpressionTree;
3131
import com.sun.source.tree.InstanceOfTree;
3232
import com.sun.source.tree.ModifiersTree;
3333
import com.sun.source.tree.ModuleTree;
@@ -59,6 +59,7 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
5959
maybeGetMethod(BindingPatternTree.class, "getType");
6060
private static final Method BINDING_PATTERN_TREE_GET_BINDING =
6161
maybeGetMethod(BindingPatternTree.class, "getBinding");
62+
private static final Method CASE_TREE_GET_LABELS = maybeGetMethod(CaseTree.class, "getLabels");
6263

6364
public Java14InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
6465
super(builder, indentMultiplier);
@@ -247,14 +248,25 @@ public Void visitCase(CaseTree node, Void unused) {
247248
sync(node);
248249
markForPartialFormat();
249250
builder.forcedBreak();
250-
if (node.getExpressions().isEmpty()) {
251+
List<? extends Tree> labels;
252+
boolean isDefault;
253+
if (CASE_TREE_GET_LABELS != null) {
254+
labels = (List<? extends Tree>) invoke(CASE_TREE_GET_LABELS, node);
255+
isDefault =
256+
labels.size() == 1
257+
&& getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL");
258+
} else {
259+
labels = node.getExpressions();
260+
isDefault = labels.isEmpty();
261+
}
262+
if (isDefault) {
251263
token("default", plusTwo);
252264
} else {
253265
token("case", plusTwo);
254-
builder.open(node.getExpressions().size() > 1 ? plusFour : ZERO);
266+
builder.open(labels.size() > 1 ? plusFour : ZERO);
255267
builder.space();
256268
boolean first = true;
257-
for (ExpressionTree expression : node.getExpressions()) {
269+
for (Tree expression : labels) {
258270
if (!first) {
259271
token(",");
260272
builder.breakOp(" ");

core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,28 @@
1414

1515
package com.google.googlejavaformat.java;
1616

17-
import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_VERSION;
18-
import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION;
17+
import static com.google.common.collect.MoreCollectors.toOptional;
1918
import static com.google.common.io.Files.getFileExtension;
2019
import static com.google.common.io.Files.getNameWithoutExtension;
2120
import static java.nio.charset.StandardCharsets.UTF_8;
2221
import static org.junit.Assert.assertEquals;
2322
import static org.junit.Assert.assertTrue;
2423
import static org.junit.Assert.fail;
2524

26-
import com.google.common.collect.ImmutableSet;
25+
import com.google.common.collect.ImmutableMultimap;
2726
import com.google.common.io.CharStreams;
2827
import com.google.common.reflect.ClassPath;
2928
import com.google.common.reflect.ClassPath.ResourceInfo;
3029
import com.google.googlejavaformat.Newlines;
3130
import java.io.IOException;
3231
import java.io.InputStream;
3332
import java.io.InputStreamReader;
34-
import java.lang.reflect.Method;
3533
import java.nio.file.Path;
3634
import java.nio.file.Paths;
3735
import java.util.ArrayList;
3836
import java.util.List;
3937
import java.util.Map;
38+
import java.util.OptionalInt;
4039
import java.util.TreeMap;
4140
import org.junit.Test;
4241
import org.junit.runner.RunWith;
@@ -47,12 +46,13 @@
4746
@RunWith(Parameterized.class)
4847
public class FormatterIntegrationTest {
4948

50-
private static final ImmutableSet<String> JAVA14_TESTS =
51-
ImmutableSet.of("I477", "Records", "RSLs", "Var", "ExpressionSwitch", "I574", "I594");
52-
53-
private static final ImmutableSet<String> JAVA15_TESTS = ImmutableSet.of("I603");
54-
55-
private static final ImmutableSet<String> JAVA16_TESTS = ImmutableSet.of("I588");
49+
private static final ImmutableMultimap<Integer, String> VERSIONED_TESTS =
50+
ImmutableMultimap.<Integer, String>builder()
51+
.putAll(14, "I477", "Records", "RSLs", "Var", "ExpressionSwitch", "I574", "I594")
52+
.putAll(15, "I603")
53+
.putAll(16, "I588")
54+
.putAll(17, "I683", "I684")
55+
.build();
5656

5757
@Parameters(name = "{index}: {0}")
5858
public static Iterable<Object[]> data() throws IOException {
@@ -91,35 +91,15 @@ public static Iterable<Object[]> data() throws IOException {
9191
String input = inputs.get(fileName);
9292
assertTrue("unmatched input", outputs.containsKey(fileName));
9393
String expectedOutput = outputs.get(fileName);
94-
if (JAVA14_TESTS.contains(fileName) && getMajor() < 14) {
95-
continue;
96-
}
97-
if (JAVA15_TESTS.contains(fileName) && getMajor() < 15) {
98-
continue;
99-
}
100-
if (JAVA16_TESTS.contains(fileName) && getMajor() < 16) {
94+
OptionalInt version = VERSIONED_TESTS.inverse().get(fileName).stream().collect(toOptional());
95+
if (version.isPresent() && Runtime.version().feature() < version.getAsInt()) {
10196
continue;
10297
}
10398
testInputs.add(new Object[] {fileName, input, expectedOutput});
10499
}
105100
return testInputs;
106101
}
107102

108-
private static int getMajor() {
109-
try {
110-
Method versionMethod = Runtime.class.getMethod("version");
111-
Object version = versionMethod.invoke(null);
112-
return (int) version.getClass().getMethod("major").invoke(version);
113-
} catch (Exception e) {
114-
// continue below
115-
}
116-
int version = (int) Double.parseDouble(JAVA_CLASS_VERSION.value());
117-
if (49 <= version && version <= 52) {
118-
return version - (49 - 5);
119-
}
120-
throw new IllegalStateException("Unknown Java version: " + JAVA_SPECIFICATION_VERSION.value());
121-
}
122-
123103
private final String name;
124104
private final String input;
125105
private final String expected;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
interface Test {
2+
3+
static class Test1 implements Test{}
4+
static class Test2 implements Test{}
5+
6+
public static void main(String[] args) {
7+
Test test = new Test1();
8+
switch (test) {
9+
case Test1 test1 -> {}
10+
case Test2 test2 -> {}
11+
default -> throw new IllegalStateException("Unexpected value: " + test);
12+
}
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
interface Test {
2+
3+
static class Test1 implements Test {}
4+
5+
static class Test2 implements Test {}
6+
7+
public static void main(String[] args) {
8+
Test test = new Test1();
9+
switch (test) {
10+
case Test1 test1 -> {}
11+
case Test2 test2 -> {}
12+
default -> throw new IllegalStateException("Unexpected value: " + test);
13+
}
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package example;
2+
3+
import example.model.SealedInterface;
4+
import example.model.TypeA;
5+
import example.model.TypeB;
6+
7+
public class Main {
8+
public void apply(SealedInterface sealedInterface) {
9+
switch(sealedInterface) {
10+
case TypeA a -> System.out.println("A!");
11+
case TypeB b -> System.out.println("B!");
12+
}
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package example;
2+
3+
import example.model.SealedInterface;
4+
import example.model.TypeA;
5+
import example.model.TypeB;
6+
7+
public class Main {
8+
public void apply(SealedInterface sealedInterface) {
9+
switch (sealedInterface) {
10+
case TypeA a -> System.out.println("A!");
11+
case TypeB b -> System.out.println("B!");
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)