Skip to content

Commit 430ba3b

Browse files
cushongoogle-java-format Team
authored andcommitted
Initial support for pattern matching in switches
Fixes #937, #880 PiperOrigin-RevId: 589140113
1 parent b86c508 commit 430ba3b

File tree

11 files changed

+198
-4
lines changed

11 files changed

+198
-4
lines changed

core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,20 @@ public Void visitBindingPattern(BindingPatternTree node, Void unused) {
8383
}
8484

8585
private void visitBindingPattern(ModifiersTree modifiers, Tree type, Name name) {
86+
builder.open(plusFour);
8687
if (modifiers != null) {
8788
List<AnnotationTree> annotations =
8889
visitModifiers(modifiers, Direction.HORIZONTAL, Optional.empty());
8990
visitAnnotations(annotations, BreakOrNot.NO, BreakOrNot.YES);
9091
}
9192
scan(type, null);
9293
builder.breakOp(" ");
93-
visit(name);
94+
if (name.isEmpty()) {
95+
token("_");
96+
} else {
97+
visit(name);
98+
}
99+
builder.close();
94100
}
95101

96102
@Override
@@ -222,6 +228,11 @@ public Void visitCase(CaseTree node, Void unused) {
222228
List<? extends CaseLabelTree> labels = node.getLabels();
223229
boolean isDefault =
224230
labels.size() == 1 && getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL");
231+
builder.open(
232+
node.getCaseKind().equals(CaseTree.CaseKind.RULE)
233+
&& !node.getBody().getKind().equals(Tree.Kind.BLOCK)
234+
? plusFour
235+
: ZERO);
225236
if (isDefault) {
226237
token("default", plusTwo);
227238
} else {
@@ -259,22 +270,24 @@ public Void visitCase(CaseTree node, Void unused) {
259270
builder.space();
260271
token("-");
261272
token(">");
262-
builder.space();
263273
if (node.getBody().getKind() == Tree.Kind.BLOCK) {
274+
builder.space();
264275
// Explicit call with {@link CollapseEmptyOrNot.YES} to handle empty case blocks.
265276
visitBlock(
266277
(BlockTree) node.getBody(),
267278
CollapseEmptyOrNot.YES,
268279
AllowLeadingBlankLine.NO,
269280
AllowTrailingBlankLine.NO);
270281
} else {
282+
builder.breakOp(" ");
271283
scan(node.getBody(), null);
272284
}
273285
builder.guessToken(";");
274286
break;
275287
default:
276288
throw new AssertionError(node.getCaseKind());
277289
}
290+
builder.close();
278291
return null;
279292
}
280293

core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
import com.google.googlejavaformat.OpsBuilder;
1818
import com.google.googlejavaformat.java.java17.Java17InputAstVisitor;
1919
import com.sun.source.tree.CaseTree;
20+
import com.sun.source.tree.ConstantCaseLabelTree;
21+
import com.sun.source.tree.DeconstructionPatternTree;
22+
import com.sun.source.tree.DefaultCaseLabelTree;
2023
import com.sun.source.tree.ExpressionTree;
24+
import com.sun.source.tree.PatternCaseLabelTree;
25+
import com.sun.source.tree.PatternTree;
2126

2227
/**
2328
* Extends {@link Java17InputAstVisitor} with support for AST nodes that were added or modified in
@@ -33,4 +38,42 @@ public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
3338
protected ExpressionTree getGuard(final CaseTree node) {
3439
return node.getGuard();
3540
}
41+
42+
@Override
43+
public Void visitDefaultCaseLabel(DefaultCaseLabelTree node, Void unused) {
44+
token("default");
45+
return null;
46+
}
47+
48+
@Override
49+
public Void visitPatternCaseLabel(PatternCaseLabelTree node, Void unused) {
50+
scan(node.getPattern(), null);
51+
return null;
52+
}
53+
54+
@Override
55+
public Void visitConstantCaseLabel(ConstantCaseLabelTree node, Void aVoid) {
56+
scan(node.getConstantExpression(), null);
57+
return null;
58+
}
59+
60+
@Override
61+
public Void visitDeconstructionPattern(DeconstructionPatternTree node, Void unused) {
62+
scan(node.getDeconstructor(), null);
63+
builder.open(plusFour);
64+
token("(");
65+
builder.breakOp();
66+
boolean first = true;
67+
for (PatternTree pattern : node.getNestedPatterns()) {
68+
if (!first) {
69+
token(",");
70+
builder.breakOp(" ");
71+
}
72+
first = false;
73+
scan(pattern, null);
74+
}
75+
builder.close();
76+
token(")");
77+
return null;
78+
}
3679
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public class FormatterIntegrationTest {
5252
.putAll(15, "I603")
5353
.putAll(16, "I588")
5454
.putAll(17, "I683", "I684", "I696")
55-
.putAll(21, "SwitchGuardClause")
55+
.putAll(
56+
21, "SwitchGuardClause", "SwitchRecord", "SwitchDouble", "SwitchUnderscore", "I880")
5657
.build();
5758

5859
@Parameters(name = "{index}: {0}")
@@ -94,7 +95,7 @@ public static Iterable<Object[]> data() throws IOException {
9495
String expectedOutput = outputs.get(fileName);
9596
Optional<Integer> version =
9697
VERSIONED_TESTS.inverse().get(fileName).stream().collect(toOptional());
97-
if (version.isPresent() && Runtime.version().feature() < version.get()) {
98+
if (Runtime.version().feature() < version.orElse(Integer.MAX_VALUE)) {
9899
continue;
99100
}
100101
testInputs.add(new Object[] {fileName, input, expectedOutput});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class I880 {
2+
public String f(int i) {
3+
return switch (i) {
4+
case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "looooooooooooooooooooooooooooooooooooooooong expression";
5+
default -> "looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong expression";
6+
};
7+
}
8+
9+
public boolean test(int i) {
10+
return switch (i) {
11+
case 0 -> // zero
12+
false;
13+
case 1 -> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".length()
14+
== 0;
15+
default -> // otherwise
16+
true;
17+
};
18+
}
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class I880 {
2+
public String f(int i) {
3+
return switch (i) {
4+
case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ->
5+
"looooooooooooooooooooooooooooooooooooooooong expression";
6+
default ->
7+
"looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong expression";
8+
};
9+
}
10+
11+
public boolean test(int i) {
12+
return switch (i) {
13+
case 0 -> // zero
14+
false;
15+
case 1 ->
16+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".length() == 0;
17+
default -> // otherwise
18+
true;
19+
};
20+
}
21+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class SwitchDouble {
2+
void x(Object o) {
3+
switch (o) {
4+
case null, default:
5+
}
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class SwitchDouble {
2+
void x(Object o) {
3+
switch (o) {
4+
case null, default:
5+
}
6+
}
7+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
record SwitchRecord(int i) {
2+
int x(Object o) {
3+
return switch (o) {
4+
case SwitchRecord(int i) -> i;
5+
default -> 0;
6+
};
7+
}
8+
int f(Object o) {
9+
return switch (o) {
10+
case SwitchRecord(int one, int two, int three, int four, int five, int six, int seven, int eight, int nine) -> nine;
11+
default -> 0;
12+
};
13+
}
14+
int g(Object o) {
15+
return switch (o) {
16+
case SwitchRecord(int one, int two, int three, int four, int five, int six, int seven, int eight, int nine) ->
17+
System.err.println("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.");
18+
default -> 0;
19+
};
20+
}
21+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
record SwitchRecord(int i) {
2+
int x(Object o) {
3+
return switch (o) {
4+
case SwitchRecord(int i) -> i;
5+
default -> 0;
6+
};
7+
}
8+
9+
int f(Object o) {
10+
return switch (o) {
11+
case SwitchRecord(
12+
int one,
13+
int two,
14+
int three,
15+
int four,
16+
int five,
17+
int six,
18+
int seven,
19+
int eight,
20+
int nine) ->
21+
nine;
22+
default -> 0;
23+
};
24+
}
25+
26+
int g(Object o) {
27+
return switch (o) {
28+
case SwitchRecord(
29+
int one,
30+
int two,
31+
int three,
32+
int four,
33+
int five,
34+
int six,
35+
int seven,
36+
int eight,
37+
int nine) ->
38+
System.err.println(
39+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor"
40+
+ " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis"
41+
+ " nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo"
42+
+ " consequat.");
43+
default -> 0;
44+
};
45+
}
46+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class SwitchUnderscore {
2+
void x(Object o) {
3+
switch (o) {
4+
case String _:
5+
default:
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)