diff --git a/core/pom.xml b/core/pom.xml
index 038e4eda..9c09d165 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -22,7 +22,7 @@
com.google.googlejavaformat
google-java-format-parent
- HEAD-SNAPSHOT
+ 1.19.0
google-java-format
@@ -226,7 +226,7 @@
jdk11
- (,17)
+ [11,17)
@@ -236,6 +236,7 @@
**/Java17InputAstVisitor.java
+ **/Java21InputAstVisitor.java
@@ -243,6 +244,32 @@
maven-javadoc-plugin
com.google.googlejavaformat.java.java17
+ com.google.googlejavaformat.java.java21
+
+
+
+
+
+
+ jdk17
+
+ [17,21)
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ **/Java21InputAstVisitor.java
+
+
+
+
+ maven-javadoc-plugin
+
+ com.google.googlejavaformat.java.java21
diff --git a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
index 9ff702d5..5aa7a123 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
@@ -151,16 +151,14 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
OpsBuilder builder = new OpsBuilder(javaInput, javaOutput);
// Output the compilation unit.
JavaInputAstVisitor visitor;
- if (Runtime.version().feature() >= 17) {
- try {
- visitor =
- Class.forName("com.google.googlejavaformat.java.java17.Java17InputAstVisitor")
- .asSubclass(JavaInputAstVisitor.class)
- .getConstructor(OpsBuilder.class, int.class)
- .newInstance(builder, options.indentationMultiplier());
- } catch (ReflectiveOperationException e) {
- throw new LinkageError(e.getMessage(), e);
- }
+ if (Runtime.version().feature() >= 21) {
+ visitor =
+ createVisitor(
+ "com.google.googlejavaformat.java.java21.Java21InputAstVisitor", builder, options);
+ } else if (Runtime.version().feature() >= 17) {
+ visitor =
+ createVisitor(
+ "com.google.googlejavaformat.java.java17.Java17InputAstVisitor", builder, options);
} else {
visitor = new JavaInputAstVisitor(builder, options.indentationMultiplier());
}
@@ -173,6 +171,18 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
javaOutput.flush();
}
+ private static JavaInputAstVisitor createVisitor(
+ final String className, final OpsBuilder builder, final JavaFormatterOptions options) {
+ try {
+ return Class.forName(className)
+ .asSubclass(JavaInputAstVisitor.class)
+ .getConstructor(OpsBuilder.class, int.class)
+ .newInstance(builder, options.indentationMultiplier());
+ } catch (ReflectiveOperationException e) {
+ throw new LinkageError(e.getMessage(), e);
+ }
+ }
+
static boolean errorDiagnostic(Diagnostic> input) {
if (input.getKind() != Diagnostic.Kind.ERROR) {
return false;
diff --git a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java
new file mode 100644
index 00000000..3c315aaf
--- /dev/null
+++ b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.googlejavaformat.java;
+
+import static com.google.common.collect.Sets.toImmutableEnumSet;
+
+import com.google.auto.service.AutoService;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.tools.Tool;
+
+/** Provide a way to be invoked without necessarily starting a new VM. */
+@AutoService(Tool.class)
+public class GoogleJavaFormatTool implements Tool {
+ @Override
+ public String name() {
+ return "google-java-format";
+ }
+
+ @Override
+ public Set getSourceVersions() {
+ return Arrays.stream(SourceVersion.values()).collect(toImmutableEnumSet());
+ }
+
+ @Override
+ public int run(InputStream in, OutputStream out, OutputStream err, String... args) {
+ PrintStream outStream = new PrintStream(out);
+ PrintStream errStream = new PrintStream(err);
+ try {
+ return Main.main(in, outStream, errStream, args);
+ } catch (RuntimeException e) {
+ errStream.print(e.getMessage());
+ errStream.flush();
+ return 1; // pass non-zero value back indicating an error has happened
+ }
+ }
+}
diff --git a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java
index 7bcad4cc..438eac59 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java
@@ -29,10 +29,11 @@ public String name() {
@Override
public int run(PrintWriter out, PrintWriter err, String... args) {
try {
- return Main.main(out, err, args);
+ return Main.main(System.in, out, err, args);
} catch (RuntimeException e) {
err.print(e.getMessage());
- return -1; // pass non-zero value back indicating an error has happened
+ err.flush();
+ return 1; // pass non-zero value back indicating an error has happened
}
}
}
diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java b/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java
index eee210e2..7b5eb841 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java
@@ -387,7 +387,14 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
final boolean isNumbered; // Is this tok numbered? (tokens and comments)
String extraNewline = null; // Extra newline at end?
List strings = new ArrayList<>();
- if (Character.isWhitespace(tokText0)) {
+ if (tokText.startsWith("'")
+ || tokText.startsWith("\"")
+ || JavacTokens.isStringFragment(t.kind())) {
+ // Perform this check first, STRINGFRAGMENT tokens can start with arbitrary characters.
+ isToken = true;
+ isNumbered = true;
+ strings.add(originalTokText);
+ } else if (Character.isWhitespace(tokText0)) {
isToken = false;
isNumbered = false;
Iterator it = Newlines.lineIterator(originalTokText);
@@ -404,10 +411,6 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept
strings.add(line);
}
}
- } else if (tokText.startsWith("'") || tokText.startsWith("\"")) {
- isToken = true;
- isNumbered = true;
- strings.add(originalTokText);
} else if (tokText.startsWith("//") || tokText.startsWith("/*")) {
// For compatibility with an earlier lexer, the newline after a // comment is its own tok.
if (tokText.startsWith("//")
diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java
index 89c944c5..ea967b3d 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java
@@ -930,7 +930,6 @@ public boolean visitEnumDeclaration(ClassTree node) {
@Override
public Void visitMemberReference(MemberReferenceTree node, Void unused) {
- sync(node);
builder.open(plusFour);
scan(node.getQualifierExpression(), null);
builder.breakOp();
@@ -3564,7 +3563,7 @@ int declareOne(
if (receiverExpression.isPresent()) {
scan(receiverExpression.get(), null);
} else {
- visit(name);
+ variableName(name);
}
builder.op(op);
}
@@ -3607,6 +3606,10 @@ int declareOne(
return baseDims;
}
+ protected void variableName(Name name) {
+ visit(name);
+ }
+
private void maybeAddDims(Deque> annotations) {
maybeAddDims(new ArrayDeque<>(), annotations);
}
@@ -3697,7 +3700,7 @@ private void declareMany(List fragments, Direction annotationDirec
builder.breakOp(" ");
builder.open(ZERO);
maybeAddDims(dims);
- visit(fragment.getName());
+ variableName(fragment.getName());
maybeAddDims(dims);
ExpressionTree initializer = fragment.getInitializer();
if (initializer != null) {
diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavacTokens.java b/core/src/main/java/com/google/googlejavaformat/java/JavacTokens.java
index ba7e3b77..dd8760b2 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavacTokens.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavacTokens.java
@@ -15,6 +15,7 @@
package com.google.googlejavaformat.java;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Arrays.stream;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -27,6 +28,7 @@
import com.sun.tools.javac.parser.Tokens.TokenKind;
import com.sun.tools.javac.parser.UnicodeReader;
import com.sun.tools.javac.util.Context;
+import java.util.Objects;
import java.util.Set;
/** A wrapper around javac's lexer. */
@@ -71,6 +73,16 @@ public String stringVal() {
}
}
+ private static final TokenKind STRINGFRAGMENT =
+ stream(TokenKind.values())
+ .filter(t -> t.name().contentEquals("STRINGFRAGMENT"))
+ .findFirst()
+ .orElse(null);
+
+ static boolean isStringFragment(TokenKind kind) {
+ return STRINGFRAGMENT != null && Objects.equals(kind, STRINGFRAGMENT);
+ }
+
/** Lex the input and return a list of {@link RawTok}s. */
public static ImmutableList getTokens(
String source, Context context, Set stopTokens) {
@@ -106,13 +118,39 @@ public static ImmutableList getTokens(
if (last < t.pos) {
tokens.add(new RawTok(null, null, last, t.pos));
}
- tokens.add(
- new RawTok(
- t.kind == TokenKind.STRINGLITERAL ? "\"" + t.stringVal() + "\"" : null,
- t.kind,
- t.pos,
- t.endPos));
- last = t.endPos;
+ int pos = t.pos;
+ int endPos = t.endPos;
+ if (isStringFragment(t.kind)) {
+ // A string template is tokenized as a series of STRINGFRAGMENT tokens containing the string
+ // literal values, followed by the tokens for the template arguments. For the formatter, we
+ // want the stream of tokens to appear in order by their start position, and also to have
+ // all the content from the original source text (including leading and trailing ", and the
+ // \ escapes from template arguments). This logic processes the token stream from javac to
+ // meet those requirements.
+ while (isStringFragment(t.kind)) {
+ endPos = t.endPos;
+ scanner.nextToken();
+ t = scanner.token();
+ }
+ // Read tokens for the string template arguments, until we read the end of the string
+ // template. The last token in a string template is always a trailing string fragment. Use
+ // lookahead to defer reading the token after the template until the next iteration of the
+ // outer loop.
+ while (scanner.token(/* lookahead= */ 1).endPos < endPos) {
+ scanner.nextToken();
+ t = scanner.token();
+ }
+ tokens.add(new RawTok(source.substring(pos, endPos), t.kind, pos, endPos));
+ last = endPos;
+ } else {
+ tokens.add(
+ new RawTok(
+ t.kind == TokenKind.STRINGLITERAL ? "\"" + t.stringVal() + "\"" : null,
+ t.kind,
+ t.pos,
+ t.endPos));
+ last = t.endPos;
+ }
} while (scanner.token().kind != TokenKind.EOF);
if (last < end) {
tokens.add(new RawTok(null, null, last, end));
diff --git a/core/src/main/java/com/google/googlejavaformat/java/Main.java b/core/src/main/java/com/google/googlejavaformat/java/Main.java
index 62423f22..0845e0ec 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/Main.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/Main.java
@@ -26,6 +26,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
+import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -66,20 +67,28 @@ public Main(PrintWriter outWriter, PrintWriter errWriter, InputStream inStream)
*
* @param args the command-line arguments
*/
- public static void main(String[] args) {
- PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out, UTF_8));
- PrintWriter err = new PrintWriter(new OutputStreamWriter(System.err, UTF_8));
- int result = main(out, err, args);
+ public static void main(String... args) {
+ int result = main(System.in, System.out, System.err, args);
System.exit(result);
}
/**
- * Package-private main entry point used this CLI program and the java.util.spi.ToolProvider
+ * Package-private main entry point used by the {@link javax.tools.Tool Tool} implementation in
+ * the same package as this Main class.
+ */
+ static int main(InputStream in, PrintStream out, PrintStream err, String... args) {
+ PrintWriter outWriter = new PrintWriter(new OutputStreamWriter(out, UTF_8));
+ PrintWriter errWriter = new PrintWriter(new OutputStreamWriter(err, UTF_8));
+ return main(in, outWriter, errWriter, args);
+ }
+
+ /**
+ * Package-private main entry point used by the {@link java.util.spi.ToolProvider ToolProvider}
* implementation in the same package as this Main class.
*/
- static int main(PrintWriter out, PrintWriter err, String... args) {
+ static int main(InputStream in, PrintWriter out, PrintWriter err, String... args) {
try {
- Main formatter = new Main(out, err, System.in);
+ Main formatter = new Main(out, err, in);
return formatter.format(args);
} catch (UsageException e) {
err.print(e.getMessage());
diff --git a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java
index d801c9b8..f241ae47 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java
@@ -15,6 +15,7 @@
package com.google.googlejavaformat.java;
import static com.google.common.collect.Iterables.getLast;
+import static java.lang.Math.min;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;
@@ -122,6 +123,10 @@ public Void visitLiteral(LiteralTree literalTree, Void aVoid) {
if (literalTree.getKind() != Kind.STRING_LITERAL) {
return null;
}
+ int pos = getStartPosition(literalTree);
+ if (input.substring(pos, min(input.length(), pos + 3)).equals("\"\"\"")) {
+ return null;
+ }
Tree parent = getCurrentPath().getParentPath().getLeaf();
if (parent instanceof MemberSelectTree
&& ((MemberSelectTree) parent).getExpression().equals(literalTree)) {
diff --git a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
index a0561e2f..6818f4a0 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
@@ -29,6 +29,7 @@
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.InstanceOfTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.ModuleTree;
@@ -82,6 +83,7 @@ public Void visitBindingPattern(BindingPatternTree node, Void unused) {
}
private void visitBindingPattern(ModifiersTree modifiers, Tree type, Name name) {
+ builder.open(plusFour);
if (modifiers != null) {
List annotations =
visitModifiers(modifiers, Direction.HORIZONTAL, Optional.empty());
@@ -89,7 +91,12 @@ private void visitBindingPattern(ModifiersTree modifiers, Tree type, Name name)
}
scan(type, null);
builder.breakOp(" ");
- visit(name);
+ if (name.isEmpty()) {
+ token("_");
+ } else {
+ visit(name);
+ }
+ builder.close();
}
@Override
@@ -221,6 +228,11 @@ public Void visitCase(CaseTree node, Void unused) {
List extends CaseLabelTree> labels = node.getLabels();
boolean isDefault =
labels.size() == 1 && getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL");
+ builder.open(
+ node.getCaseKind().equals(CaseTree.CaseKind.RULE)
+ && !node.getBody().getKind().equals(Tree.Kind.BLOCK)
+ ? plusFour
+ : ZERO);
if (isDefault) {
token("default", plusTwo);
} else {
@@ -238,6 +250,15 @@ public Void visitCase(CaseTree node, Void unused) {
}
builder.close();
}
+
+ final ExpressionTree guard = getGuard(node);
+ if (guard != null) {
+ builder.space();
+ token("when");
+ builder.space();
+ scan(guard, null);
+ }
+
switch (node.getCaseKind()) {
case STATEMENT:
token(":");
@@ -249,8 +270,8 @@ public Void visitCase(CaseTree node, Void unused) {
builder.space();
token("-");
token(">");
- builder.space();
if (node.getBody().getKind() == Tree.Kind.BLOCK) {
+ builder.space();
// Explicit call with {@link CollapseEmptyOrNot.YES} to handle empty case blocks.
visitBlock(
(BlockTree) node.getBody(),
@@ -258,6 +279,7 @@ public Void visitCase(CaseTree node, Void unused) {
AllowLeadingBlankLine.NO,
AllowTrailingBlankLine.NO);
} else {
+ builder.breakOp(" ");
scan(node.getBody(), null);
}
builder.guessToken(";");
@@ -265,6 +287,11 @@ public Void visitCase(CaseTree node, Void unused) {
default:
throw new AssertionError(node.getCaseKind());
}
+ builder.close();
+ return null;
+ }
+
+ protected ExpressionTree getGuard(final CaseTree node) {
return null;
}
}
diff --git a/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java
new file mode 100644
index 00000000..897d6ffc
--- /dev/null
+++ b/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 The google-java-format Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.googlejavaformat.java.java21;
+
+import com.google.googlejavaformat.OpsBuilder;
+import com.google.googlejavaformat.java.java17.Java17InputAstVisitor;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.ConstantCaseLabelTree;
+import com.sun.source.tree.DeconstructionPatternTree;
+import com.sun.source.tree.DefaultCaseLabelTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.PatternCaseLabelTree;
+import com.sun.source.tree.PatternTree;
+import com.sun.source.tree.StringTemplateTree;
+import javax.lang.model.element.Name;
+
+/**
+ * Extends {@link Java17InputAstVisitor} with support for AST nodes that were added or modified in
+ * Java 21.
+ */
+public class Java21InputAstVisitor extends Java17InputAstVisitor {
+
+ public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
+ super(builder, indentMultiplier);
+ }
+
+ @Override
+ protected ExpressionTree getGuard(final CaseTree node) {
+ return node.getGuard();
+ }
+
+ @Override
+ public Void visitDefaultCaseLabel(DefaultCaseLabelTree node, Void unused) {
+ token("default");
+ return null;
+ }
+
+ @Override
+ public Void visitPatternCaseLabel(PatternCaseLabelTree node, Void unused) {
+ scan(node.getPattern(), null);
+ return null;
+ }
+
+ @Override
+ public Void visitConstantCaseLabel(ConstantCaseLabelTree node, Void aVoid) {
+ scan(node.getConstantExpression(), null);
+ return null;
+ }
+
+ @Override
+ public Void visitDeconstructionPattern(DeconstructionPatternTree node, Void unused) {
+ sync(node);
+ scan(node.getDeconstructor(), null);
+ builder.open(plusFour);
+ token("(");
+ builder.breakOp();
+ boolean first = true;
+ for (PatternTree pattern : node.getNestedPatterns()) {
+ if (!first) {
+ token(",");
+ builder.breakOp(" ");
+ }
+ first = false;
+ scan(pattern, null);
+ }
+ builder.close();
+ token(")");
+ return null;
+ }
+
+ @SuppressWarnings("preview")
+ @Override
+ public Void visitStringTemplate(StringTemplateTree node, Void aVoid) {
+ sync(node);
+ scan(node.getProcessor(), null);
+ token(".");
+ token(builder.peekToken().get());
+ return null;
+ }
+
+ @Override
+ protected void variableName(Name name) {
+ if (name.isEmpty()) {
+ token("_");
+ } else {
+ visit(name);
+ }
+ }
+}
diff --git a/core/src/main/resources/META-INF/native-image/reflect-config.json b/core/src/main/resources/META-INF/native-image/reflect-config.json
index 2c658034..4d30840f 100644
--- a/core/src/main/resources/META-INF/native-image/reflect-config.json
+++ b/core/src/main/resources/META-INF/native-image/reflect-config.json
@@ -2,5 +2,23 @@
{
"name": "com.sun.tools.javac.parser.UnicodeReader",
"allDeclaredMethods": true
+ },
+ {
+ "name": "com.google.googlejavaformat.java.java17.Java17InputAstVisitor",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": ["com.google.googlejavaformat.OpsBuilder", "int"]
+ }
+ ]
+ },
+ {
+ "name": "com.google.googlejavaformat.java.java21.Java21InputAstVisitor",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": ["com.google.googlejavaformat.OpsBuilder", "int"]
+ }
+ ]
}
]
diff --git a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
index 61a43468..cf15ecbc 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java
@@ -52,6 +52,15 @@ public class FormatterIntegrationTest {
.putAll(15, "I603")
.putAll(16, "I588")
.putAll(17, "I683", "I684", "I696")
+ .putAll(
+ 21,
+ "SwitchGuardClause",
+ "SwitchRecord",
+ "SwitchDouble",
+ "SwitchUnderscore",
+ "I880",
+ "Unnamed",
+ "I981")
.build();
@Parameters(name = "{index}: {0}")
@@ -93,7 +102,7 @@ public static Iterable