Skip to content

Commit b86c508

Browse files
TheCKgoogle-java-format Team
authored andcommitted
Add support for guard clauses in Java 21 switch expressions
This PR adds support for `switch` statements where a `case` has a guard clause. See Issue #983 Fixes #988 COPYBARA_INTEGRATE_REVIEW=#988 from TheCK:master 4771486 PiperOrigin-RevId: 588913297
1 parent ad77154 commit b86c508

File tree

7 files changed

+117
-11
lines changed

7 files changed

+117
-11
lines changed

core/pom.xml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@
226226
<profile>
227227
<id>jdk11</id>
228228
<activation>
229-
<jdk>(,17)</jdk>
229+
<jdk>[11,17)</jdk>
230230
</activation>
231231
<build>
232232
<plugins>
@@ -236,13 +236,40 @@
236236
<configuration>
237237
<excludes>
238238
<exclude>**/Java17InputAstVisitor.java</exclude>
239+
<exclude>**/Java21InputAstVisitor.java</exclude>
239240
</excludes>
240241
</configuration>
241242
</plugin>
242243
<plugin>
243244
<artifactId>maven-javadoc-plugin</artifactId>
244245
<configuration>
245246
<excludePackageNames>com.google.googlejavaformat.java.java17</excludePackageNames>
247+
<excludePackageNames>com.google.googlejavaformat.java.java21</excludePackageNames>
248+
</configuration>
249+
</plugin>
250+
</plugins>
251+
</build>
252+
</profile>
253+
<profile>
254+
<id>jdk17</id>
255+
<activation>
256+
<jdk>[17,21)</jdk>
257+
</activation>
258+
<build>
259+
<plugins>
260+
<plugin>
261+
<groupId>org.apache.maven.plugins</groupId>
262+
<artifactId>maven-compiler-plugin</artifactId>
263+
<configuration>
264+
<excludes>
265+
<exclude>**/Java21InputAstVisitor.java</exclude>
266+
</excludes>
267+
</configuration>
268+
</plugin>
269+
<plugin>
270+
<artifactId>maven-javadoc-plugin</artifactId>
271+
<configuration>
272+
<excludePackageNames>com.google.googlejavaformat.java.java21</excludePackageNames>
246273
</configuration>
247274
</plugin>
248275
</plugins>

core/src/main/java/com/google/googlejavaformat/java/Formatter.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,14 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
151151
OpsBuilder builder = new OpsBuilder(javaInput, javaOutput);
152152
// Output the compilation unit.
153153
JavaInputAstVisitor visitor;
154-
if (Runtime.version().feature() >= 17) {
155-
try {
156-
visitor =
157-
Class.forName("com.google.googlejavaformat.java.java17.Java17InputAstVisitor")
158-
.asSubclass(JavaInputAstVisitor.class)
159-
.getConstructor(OpsBuilder.class, int.class)
160-
.newInstance(builder, options.indentationMultiplier());
161-
} catch (ReflectiveOperationException e) {
162-
throw new LinkageError(e.getMessage(), e);
163-
}
154+
if (Runtime.version().feature() >= 21) {
155+
visitor =
156+
createVisitor(
157+
"com.google.googlejavaformat.java.java21.Java21InputAstVisitor", builder, options);
158+
} else if (Runtime.version().feature() >= 17) {
159+
visitor =
160+
createVisitor(
161+
"com.google.googlejavaformat.java.java17.Java17InputAstVisitor", builder, options);
164162
} else {
165163
visitor = new JavaInputAstVisitor(builder, options.indentationMultiplier());
166164
}
@@ -173,6 +171,18 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
173171
javaOutput.flush();
174172
}
175173

174+
private static JavaInputAstVisitor createVisitor(
175+
final String className, final OpsBuilder builder, final JavaFormatterOptions options) {
176+
try {
177+
return Class.forName(className)
178+
.asSubclass(JavaInputAstVisitor.class)
179+
.getConstructor(OpsBuilder.class, int.class)
180+
.newInstance(builder, options.indentationMultiplier());
181+
} catch (ReflectiveOperationException e) {
182+
throw new LinkageError(e.getMessage(), e);
183+
}
184+
}
185+
176186
static boolean errorDiagnostic(Diagnostic<?> input) {
177187
if (input.getKind() != Diagnostic.Kind.ERROR) {
178188
return false;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.sun.source.tree.CaseTree;
3030
import com.sun.source.tree.ClassTree;
3131
import com.sun.source.tree.CompilationUnitTree;
32+
import com.sun.source.tree.ExpressionTree;
3233
import com.sun.source.tree.InstanceOfTree;
3334
import com.sun.source.tree.ModifiersTree;
3435
import com.sun.source.tree.ModuleTree;
@@ -238,6 +239,15 @@ public Void visitCase(CaseTree node, Void unused) {
238239
}
239240
builder.close();
240241
}
242+
243+
final ExpressionTree guard = getGuard(node);
244+
if (guard != null) {
245+
builder.space();
246+
token("when");
247+
builder.space();
248+
scan(guard, null);
249+
}
250+
241251
switch (node.getCaseKind()) {
242252
case STATEMENT:
243253
token(":");
@@ -267,4 +277,8 @@ public Void visitCase(CaseTree node, Void unused) {
267277
}
268278
return null;
269279
}
280+
281+
protected ExpressionTree getGuard(final CaseTree node) {
282+
return null;
283+
}
270284
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2023 The google-java-format Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
package com.google.googlejavaformat.java.java21;
16+
17+
import com.google.googlejavaformat.OpsBuilder;
18+
import com.google.googlejavaformat.java.java17.Java17InputAstVisitor;
19+
import com.sun.source.tree.CaseTree;
20+
import com.sun.source.tree.ExpressionTree;
21+
22+
/**
23+
* Extends {@link Java17InputAstVisitor} with support for AST nodes that were added or modified in
24+
* Java 21.
25+
*/
26+
public class Java21InputAstVisitor extends Java17InputAstVisitor {
27+
28+
public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
29+
super(builder, indentMultiplier);
30+
}
31+
32+
@Override
33+
protected ExpressionTree getGuard(final CaseTree node) {
34+
return node.getGuard();
35+
}
36+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class FormatterIntegrationTest {
5252
.putAll(15, "I603")
5353
.putAll(16, "I588")
5454
.putAll(17, "I683", "I684", "I696")
55+
.putAll(21, "SwitchGuardClause")
5556
.build();
5657

5758
@Parameters(name = "{index}: {0}")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class SwitchGuardClause {
2+
boolean test(Object x) {
3+
return switch (x) {
4+
case String s when s.length() < 5 -> true;
5+
case Integer i -> false;
6+
default -> true;
7+
};
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class SwitchGuardClause {
2+
boolean test(Object x) {
3+
return switch (x) {
4+
case String s when s.length() < 5 -> true;
5+
case Integer i -> false;
6+
default -> true;
7+
};
8+
}
9+
}

0 commit comments

Comments
 (0)