aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/pom.xml40
-rw-r--r--core/src/main/java/com/google/googlejavaformat/CommentsHelper.java19
-rw-r--r--core/src/main/java/com/google/googlejavaformat/Doc.java34
-rw-r--r--core/src/main/java/com/google/googlejavaformat/OpsBuilder.java2
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java57
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/Formatter.java40
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatTool.java53
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProvider.java5
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java10
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java50
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavaInput.java17
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java19
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java2
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/JavacTokens.java52
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/Main.java102
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java28
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java11
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java (renamed from core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java)109
-rw-r--r--core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java101
-rw-r--r--core/src/main/resources/META-INF/native-image/reflect-config.json18
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java11
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java2
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java65
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/MainTest.java32
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/PartialFormattingTest.java1
-rw-r--r--core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java21
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.input2
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.output2
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B21283374.output56
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B26694550.output6
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B27246427.output1
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.input7
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.output8
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.input23
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.output23
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.input6
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.output6
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.input7
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.output8
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.input19
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.output21
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.input5
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.output5
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.input12
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.output14
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/M.output108
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.input29
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.output38
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.input7
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.output7
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input9
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output9
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.input21
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.output46
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.input8
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.output8
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.input44
-rw-r--r--core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.output48
58 files changed, 1195 insertions, 319 deletions
diff --git a/core/pom.xml b/core/pom.xml
index 1d47159..d1363fe 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -102,13 +102,12 @@
<link>https://docs.oracle.com/en/java/javase/11/docs/api</link>
</links>
<additionalJOptions>
+ <additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
+ <additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
- <additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
- <additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
- <additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED,com.google.googlejavaformat</additionalJOption>
</additionalJOptions>
</configuration>
<executions>
@@ -227,7 +226,34 @@
<profile>
<id>jdk11</id>
<activation>
- <jdk>(,14)</jdk>
+ <jdk>[11,17)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/Java17InputAstVisitor.java</exclude>
+ <exclude>**/Java21InputAstVisitor.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>com.google.googlejavaformat.java.java17</excludePackageNames>
+ <excludePackageNames>com.google.googlejavaformat.java.java21</excludePackageNames>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>jdk17</id>
+ <activation>
+ <jdk>[17,21)</jdk>
</activation>
<build>
<plugins>
@@ -236,14 +262,14 @@
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
- <exclude>**/Java14InputAstVisitor.java</exclude>
+ <exclude>**/Java21InputAstVisitor.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
- <excludePackageNames>com.google.googlejavaformat.java.java14</excludePackageNames>
+ <excludePackageNames>com.google.googlejavaformat.java.java21</excludePackageNames>
</configuration>
</plugin>
</plugins>
@@ -256,7 +282,7 @@
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
- <version>0.9.9</version>
+ <version>0.9.13</version>
<extensions>true</extensions>
<executions>
<execution>
diff --git a/core/src/main/java/com/google/googlejavaformat/CommentsHelper.java b/core/src/main/java/com/google/googlejavaformat/CommentsHelper.java
index 45e507b..1e33003 100644
--- a/core/src/main/java/com/google/googlejavaformat/CommentsHelper.java
+++ b/core/src/main/java/com/google/googlejavaformat/CommentsHelper.java
@@ -14,6 +14,10 @@
package com.google.googlejavaformat;
+import com.google.googlejavaformat.Input.Tok;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
/**
* Rewrite comments. This interface is implemented by {@link
* com.google.googlejavaformat.java.JavaCommentsHelper JavaCommentsHelper}.
@@ -28,4 +32,19 @@ public interface CommentsHelper {
* @return the rewritten comment
*/
String rewrite(Input.Tok tok, int maxWidth, int column0);
+
+ static Optional<String> reformatParameterComment(Tok tok) {
+ if (!tok.isSlashStarComment()) {
+ return Optional.empty();
+ }
+ var match = PARAMETER_COMMENT.matcher(tok.getOriginalText());
+ if (!match.matches()) {
+ return Optional.empty();
+ }
+ return Optional.of(String.format("/* %s= */", match.group(1)));
+ }
+
+ Pattern PARAMETER_COMMENT =
+ Pattern.compile(
+ "/\\*\\s*(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(\\Q...\\E)?)\\s*=\\s*\\*/");
}
diff --git a/core/src/main/java/com/google/googlejavaformat/Doc.java b/core/src/main/java/com/google/googlejavaformat/Doc.java
index 35acca3..cab6885 100644
--- a/core/src/main/java/com/google/googlejavaformat/Doc.java
+++ b/core/src/main/java/com/google/googlejavaformat/Doc.java
@@ -15,9 +15,12 @@
package com.google.googlejavaformat;
import static com.google.common.collect.Iterables.getLast;
+import static com.google.googlejavaformat.CommentsHelper.reformatParameterComment;
import static java.lang.Math.max;
import com.google.common.base.MoreObjects;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Iterators;
import com.google.common.collect.Range;
@@ -101,16 +104,13 @@ public abstract class Doc {
private static final DiscreteDomain<Integer> INTEGERS = DiscreteDomain.integers();
// Memoized width; Float.POSITIVE_INFINITY if contains forced breaks.
- private boolean widthComputed = false;
- private float width = 0.0F;
+ private final Supplier<Float> width = Suppliers.memoize(this::computeWidth);
// Memoized flat; not defined (and never computed) if contains forced breaks.
- private boolean flatComputed = false;
- private String flat = "";
+ private final Supplier<String> flat = Suppliers.memoize(this::computeFlat);
// Memoized Range.
- private boolean rangeComputed = false;
- private Range<Integer> range = EMPTY_RANGE;
+ private final Supplier<Range<Integer>> range = Suppliers.memoize(this::computeRange);
/**
* Return the width of a {@code Doc}, or {@code Float.POSITIVE_INFINITY} if it must be broken.
@@ -118,11 +118,7 @@ public abstract class Doc {
* @return the width
*/
final float getWidth() {
- if (!widthComputed) {
- width = computeWidth();
- widthComputed = true;
- }
- return width;
+ return width.get();
}
/**
@@ -132,11 +128,7 @@ public abstract class Doc {
* @return the flat-string value
*/
final String getFlat() {
- if (!flatComputed) {
- flat = computeFlat();
- flatComputed = true;
- }
- return flat;
+ return flat.get();
}
/**
@@ -145,11 +137,7 @@ public abstract class Doc {
* @return the {@code Doc}'s {@link Range}
*/
final Range<Integer> range() {
- if (!rangeComputed) {
- range = computeRange();
- rangeComputed = true;
- }
- return range;
+ return range.get();
}
/**
@@ -727,7 +715,7 @@ public abstract class Doc {
// Account for line comments with missing spaces, see computeFlat.
return tok.length() + 1;
} else {
- return tok.length();
+ return reformatParameterComment(tok).map(String::length).orElse(tok.length());
}
}
return idx != -1 ? Float.POSITIVE_INFINITY : (float) tok.length();
@@ -741,7 +729,7 @@ public abstract class Doc {
if (tok.isSlashSlashComment() && !tok.getOriginalText().startsWith("// ")) {
return "// " + tok.getOriginalText().substring("//".length());
}
- return tok.getOriginalText();
+ return reformatParameterComment(tok).orElse(tok.getOriginalText());
}
@Override
diff --git a/core/src/main/java/com/google/googlejavaformat/OpsBuilder.java b/core/src/main/java/com/google/googlejavaformat/OpsBuilder.java
index db431c0..a45e83b 100644
--- a/core/src/main/java/com/google/googlejavaformat/OpsBuilder.java
+++ b/core/src/main/java/com/google/googlejavaformat/OpsBuilder.java
@@ -159,7 +159,7 @@ public final class OpsBuilder {
int depth = 0;
/** Add an {@link Op}, and record open/close ops for later validation of unclosed levels. */
- private void add(Op op) {
+ public final void add(Op op) {
if (op instanceof OpenOp) {
depth++;
} else if (op instanceof CloseOp) {
diff --git a/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java b/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java
index 9d8ae41..3d68a23 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/FormatFileCallable.java
@@ -14,40 +14,73 @@
package com.google.googlejavaformat.java;
+import com.google.auto.value.AutoValue;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
+import java.nio.file.Path;
import java.util.concurrent.Callable;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Encapsulates information about a file to be formatted, including which parts of the file to
* format.
*/
-class FormatFileCallable implements Callable<String> {
+class FormatFileCallable implements Callable<FormatFileCallable.Result> {
+
+ @AutoValue
+ abstract static class Result {
+ abstract @Nullable Path path();
+
+ abstract String input();
+
+ abstract @Nullable String output();
+
+ boolean changed() {
+ return !input().equals(output());
+ }
+
+ abstract @Nullable FormatterException exception();
+
+ static Result create(
+ @Nullable Path path,
+ String input,
+ @Nullable String output,
+ @Nullable FormatterException exception) {
+ return new AutoValue_FormatFileCallable_Result(path, input, output, exception);
+ }
+ }
+
+ private final Path path;
private final String input;
private final CommandLineOptions parameters;
private final JavaFormatterOptions options;
public FormatFileCallable(
- CommandLineOptions parameters, String input, JavaFormatterOptions options) {
+ CommandLineOptions parameters, Path path, String input, JavaFormatterOptions options) {
+ this.path = path;
this.input = input;
this.parameters = parameters;
this.options = options;
}
@Override
- public String call() throws FormatterException {
- if (parameters.fixImportsOnly()) {
- return fixImports(input);
- }
+ public Result call() {
+ try {
+ if (parameters.fixImportsOnly()) {
+ return Result.create(path, input, fixImports(input), /* exception= */ null);
+ }
- Formatter formatter = new Formatter(options);
- String formatted = formatter.formatSource(input, characterRanges(input).asRanges());
- formatted = fixImports(formatted);
- if (parameters.reflowLongStrings()) {
- formatted = StringWrapper.wrap(Formatter.MAX_LINE_LENGTH, formatted, formatter);
+ Formatter formatter = new Formatter(options);
+ String formatted = formatter.formatSource(input, characterRanges(input).asRanges());
+ formatted = fixImports(formatted);
+ if (parameters.reflowLongStrings()) {
+ formatted = StringWrapper.wrap(Formatter.MAX_LINE_LENGTH, formatted, formatter);
+ }
+ return Result.create(path, input, formatted, /* exception= */ null);
+ } catch (FormatterException e) {
+ return Result.create(path, input, /* output= */ null, e);
}
- return formatted;
}
private String fixImports(String input) throws FormatterException {
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 aac829d..5aa7a12 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java
@@ -136,9 +136,9 @@ public final class Formatter {
JavacParser parser =
parserFactory.newParser(
javaInput.getText(),
- /*keepDocComments=*/ true,
- /*keepEndPos=*/ true,
- /*keepLineMap=*/ true);
+ /* keepDocComments= */ true,
+ /* keepEndPos= */ true,
+ /* keepLineMap= */ true);
unit = parser.parseCompilationUnit();
unit.sourcefile = source;
@@ -151,16 +151,14 @@ public final class Formatter {
OpsBuilder builder = new OpsBuilder(javaInput, javaOutput);
// Output the compilation unit.
JavaInputAstVisitor visitor;
- if (Runtime.version().feature() >= 14) {
- try {
- visitor =
- Class.forName("com.google.googlejavaformat.java.java14.Java14InputAstVisitor")
- .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 final class Formatter {
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;
@@ -262,7 +272,9 @@ public final class Formatter {
// TODO(cushon): this is only safe because the modifier ordering doesn't affect whitespace,
// and doesn't change the replacements that are output. This is not true in general for
// 'de-linting' changes (e.g. import ordering).
- javaInput = ModifierOrderer.reorderModifiers(javaInput, characterRanges);
+ if (options.reorderModifiers()) {
+ javaInput = ModifierOrderer.reorderModifiers(javaInput, characterRanges);
+ }
String lineSeparator = Newlines.guessLineSeparator(input);
JavaOutput javaOutput =
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 0000000..3c315aa
--- /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<SourceVersion> 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 7bcad4c..438eac5 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 class GoogleJavaFormatToolProvider implements ToolProvider {
@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/JavaCommentsHelper.java b/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java
index 346324a..d34ecc4 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaCommentsHelper.java
@@ -53,11 +53,13 @@ public final class JavaCommentsHelper implements CommentsHelper {
}
if (tok.isSlashSlashComment()) {
return indentLineComments(lines, column0);
- } else if (javadocShaped(lines)) {
- return indentJavadoc(lines, column0);
- } else {
- return preserveIndentation(lines, column0);
}
+ return CommentsHelper.reformatParameterComment(tok)
+ .orElseGet(
+ () ->
+ javadocShaped(lines)
+ ? indentJavadoc(lines, column0)
+ : preserveIndentation(lines, column0));
}
// For non-javadoc-shaped block comments, shift the entire block to the correct
diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java b/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java
index fbb6fe7..67c13d0 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaFormatterOptions.java
@@ -14,6 +14,7 @@
package com.google.googlejavaformat.java;
+import com.google.auto.value.AutoValue;
import com.google.errorprone.annotations.Immutable;
/**
@@ -27,7 +28,8 @@ import com.google.errorprone.annotations.Immutable;
* preferences, and in fact it would work directly against our primary goals.
*/
@Immutable
-public class JavaFormatterOptions {
+@AutoValue
+public abstract class JavaFormatterOptions {
public enum Style {
/** The default Google Java Style configuration. */
@@ -47,27 +49,17 @@ public class JavaFormatterOptions {
}
}
- private final Style style;
- private final boolean formatJavadoc;
-
- private JavaFormatterOptions(Style style, boolean formatJavadoc) {
- this.style = style;
- this.formatJavadoc = formatJavadoc;
- }
-
/** Returns the multiplier for the unit of indent. */
public int indentationMultiplier() {
- return style.indentationMultiplier();
+ return style().indentationMultiplier();
}
- public boolean formatJavadoc() {
- return formatJavadoc;
- }
+ public abstract boolean formatJavadoc();
+
+ public abstract boolean reorderModifiers();
/** Returns the code style. */
- public Style style() {
- return style;
- }
+ public abstract Style style();
/** Returns the default formatting options. */
public static JavaFormatterOptions defaultOptions() {
@@ -76,28 +68,22 @@ public class JavaFormatterOptions {
/** Returns a builder for {@link JavaFormatterOptions}. */
public static Builder builder() {
- return new Builder();
+ return new AutoValue_JavaFormatterOptions.Builder()
+ .style(Style.GOOGLE)
+ .formatJavadoc(true)
+ .reorderModifiers(true);
}
/** A builder for {@link JavaFormatterOptions}. */
- public static class Builder {
- private Style style = Style.GOOGLE;
- private boolean formatJavadoc = true;
+ @AutoValue.Builder
+ public abstract static class Builder {
- private Builder() {}
+ public abstract Builder style(Style style);
- public Builder style(Style style) {
- this.style = style;
- return this;
- }
+ public abstract Builder formatJavadoc(boolean formatJavadoc);
- public Builder formatJavadoc(boolean formatJavadoc) {
- this.formatJavadoc = formatJavadoc;
- return this;
- }
+ public abstract Builder reorderModifiers(boolean reorderModifiers);
- public JavaFormatterOptions build() {
- return new JavaFormatterOptions(style, formatJavadoc);
- }
+ public abstract JavaFormatterOptions build();
}
}
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 165bdeb..7b5eb84 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java
@@ -49,6 +49,7 @@ import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
@@ -349,7 +350,8 @@ public final class JavaInput extends Input {
stopTokens = ImmutableSet.<TokenKind>builder().addAll(stopTokens).add(TokenKind.EOF).build();
Context context = new Context();
Options.instance(context).put("--enable-preview", "true");
- new JavacFileManager(context, true, UTF_8);
+ JavaFileManager fileManager = new JavacFileManager(context, false, UTF_8);
+ context.put(JavaFileManager.class, fileManager);
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
context.put(DiagnosticListener.class, diagnosticCollector);
Log log = Log.instance(context);
@@ -385,7 +387,14 @@ public final class JavaInput extends Input {
final boolean isNumbered; // Is this tok numbered? (tokens and comments)
String extraNewline = null; // Extra newline at end?
List<String> 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<String> it = Newlines.lineIterator(originalTokText);
@@ -402,10 +411,6 @@ public final class JavaInput extends Input {
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 daed250..ea967b3 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java
@@ -285,7 +285,10 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
ImmutableSetMultimap.Builder<String, String> result = ImmutableSetMultimap.builder();
for (String annotation :
ImmutableList.of(
+ "org.jspecify.annotations.NonNull",
+ "org.jspecify.annotations.Nullable",
"org.jspecify.nullness.Nullable",
+ "org.checkerframework.checker.nullness.qual.NonNull",
"org.checkerframework.checker.nullness.qual.Nullable")) {
String simpleName = annotation.substring(annotation.lastIndexOf('.') + 1);
result.put(simpleName, annotation);
@@ -927,7 +930,6 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
@Override
public Void visitMemberReference(MemberReferenceTree node, Void unused) {
- sync(node);
builder.open(plusFour);
scan(node.getQualifierExpression(), null);
builder.breakOp();
@@ -1247,7 +1249,10 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
token(",");
builder.breakOp(" ");
}
- scan(parameter, null);
+ visitVariables(
+ ImmutableList.of(parameter),
+ DeclarationKind.NONE,
+ fieldAnnotationDirection(parameter.getModifiers()));
first = false;
}
if (parens) {
@@ -2639,7 +2644,7 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
for (ExpressionTree thrownExceptionType : thrownExceptionTypes) {
if (!first) {
token(",");
- builder.breakToFill(" ");
+ builder.breakOp(" ");
}
scan(thrownExceptionType, null);
first = false;
@@ -3558,7 +3563,7 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
if (receiverExpression.isPresent()) {
scan(receiverExpression.get(), null);
} else {
- visit(name);
+ variableName(name);
}
builder.op(op);
}
@@ -3601,6 +3606,10 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
return baseDims;
}
+ protected void variableName(Name name) {
+ visit(name);
+ }
+
private void maybeAddDims(Deque<List<? extends AnnotationTree>> annotations) {
maybeAddDims(new ArrayDeque<>(), annotations);
}
@@ -3691,7 +3700,7 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
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/JavaOutput.java b/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java
index c43a91a..656b65c 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/JavaOutput.java
@@ -111,7 +111,7 @@ public final class JavaOutput extends Output {
* there's a blank line here and it's a comment.
*/
BlankLineWanted wanted = blankLines.getOrDefault(lastK, BlankLineWanted.NO);
- if (isComment(text) ? sawNewlines : wanted.wanted().orElse(sawNewlines)) {
+ if ((sawNewlines && isComment(text)) || wanted.wanted().orElse(sawNewlines)) {
++newlinesPending;
}
}
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 ba7e3b7..dd8760b 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.Token;
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 @@ class JavacTokens {
}
}
+ 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<RawTok> getTokens(
String source, Context context, Set<TokenKind> stopTokens) {
@@ -106,13 +118,39 @@ class JavacTokens {
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 953ca58..0845e0e 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/Main.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/Main.java
@@ -16,25 +16,30 @@ package com.google.googlejavaformat.java;
import static java.lang.Math.min;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Comparator.comparing;
import com.google.common.io.ByteStreams;
+import com.google.common.util.concurrent.MoreExecutors;
import com.google.googlejavaformat.FormatterDiagnostic;
import com.google.googlejavaformat.java.JavaFormatterOptions.Style;
import java.io.IOError;
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;
import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
/** The main class for the Java formatter CLI. */
public final class Main {
@@ -62,24 +67,33 @@ public final class Main {
*
* @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());
- return 0;
+ // We return exit code 2 to differentiate usage issues from code formatting issues.
+ return 2;
} finally {
err.flush();
out.flush();
@@ -120,50 +134,55 @@ public final class Main {
int numThreads = min(MAX_THREADS, parameters.files().size());
ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
- Map<Path, String> inputs = new LinkedHashMap<>();
- Map<Path, Future<String>> results = new LinkedHashMap<>();
+ ExecutorCompletionService<FormatFileCallable.Result> cs =
+ new ExecutorCompletionService<>(executorService);
boolean allOk = true;
+ int files = 0;
for (String fileName : parameters.files()) {
if (!fileName.endsWith(".java")) {
errWriter.println("Skipping non-Java file: " + fileName);
continue;
}
Path path = Paths.get(fileName);
- String input;
try {
- input = new String(Files.readAllBytes(path), UTF_8);
- inputs.put(path, input);
- results.put(
- path, executorService.submit(new FormatFileCallable(parameters, input, options)));
+ String input = new String(Files.readAllBytes(path), UTF_8);
+ cs.submit(new FormatFileCallable(parameters, path, input, options));
+ files++;
} catch (IOException e) {
errWriter.println(fileName + ": could not read file: " + e.getMessage());
allOk = false;
}
}
- for (Map.Entry<Path, Future<String>> result : results.entrySet()) {
- Path path = result.getKey();
- String formatted;
+ List<FormatFileCallable.Result> results = new ArrayList<>();
+ while (files > 0) {
try {
- formatted = result.getValue().get();
+ files--;
+ results.add(cs.take().get());
} catch (InterruptedException e) {
errWriter.println(e.getMessage());
allOk = false;
continue;
} catch (ExecutionException e) {
- if (e.getCause() instanceof FormatterException) {
- for (FormatterDiagnostic diagnostic : ((FormatterException) e.getCause()).diagnostics()) {
- errWriter.println(path + ":" + diagnostic);
- }
- } else {
- errWriter.println(path + ": error: " + e.getCause().getMessage());
- e.getCause().printStackTrace(errWriter);
+ errWriter.println("error: " + e.getCause().getMessage());
+ e.getCause().printStackTrace(errWriter);
+ allOk = false;
+ continue;
+ }
+ }
+ Collections.sort(results, comparing(FormatFileCallable.Result::path));
+ for (FormatFileCallable.Result result : results) {
+ Path path = result.path();
+ if (result.exception() != null) {
+ for (FormatterDiagnostic diagnostic : result.exception().diagnostics()) {
+ errWriter.println(path + ":" + diagnostic);
}
allOk = false;
continue;
}
- boolean changed = !formatted.equals(inputs.get(path));
+ String formatted = result.output();
+ boolean changed = result.changed();
if (changed && parameters.setExitIfChanged()) {
allOk = false;
}
@@ -186,6 +205,10 @@ public final class Main {
outWriter.write(formatted);
}
}
+ if (!MoreExecutors.shutdownAndAwaitTermination(executorService, Duration.ofSeconds(5))) {
+ errWriter.println("Failed to shut down ExecutorService");
+ allOk = false;
+ }
return allOk ? 0 : 1;
}
@@ -198,9 +221,16 @@ public final class Main {
}
String stdinFilename = parameters.assumeFilename().orElse(STDIN_FILENAME);
boolean ok = true;
- try {
- String output = new FormatFileCallable(parameters, input, options).call();
- boolean changed = !input.equals(output);
+ FormatFileCallable.Result result =
+ new FormatFileCallable(parameters, null, input, options).call();
+ if (result.exception() != null) {
+ for (FormatterDiagnostic diagnostic : result.exception().diagnostics()) {
+ errWriter.println(stdinFilename + ":" + diagnostic);
+ }
+ ok = false;
+ } else {
+ String output = result.output();
+ boolean changed = result.changed();
if (changed && parameters.setExitIfChanged()) {
ok = false;
}
@@ -211,12 +241,6 @@ public final class Main {
} else {
outWriter.write(output);
}
- } catch (FormatterException e) {
- for (FormatterDiagnostic diagnostic : e.diagnostics()) {
- errWriter.println(stdinFilename + ":" + diagnostic);
- }
- ok = false;
- // TODO(cpovirk): Catch other types of exception (as we do in the formatFiles case).
}
return ok ? 0 : 1;
}
diff --git a/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java b/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java
index 20e55e9..a0fc2f5 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/RemoveUnusedImports.java
@@ -49,7 +49,6 @@ import com.sun.tools.javac.tree.DCTree.DCReference;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
-import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
@@ -252,7 +251,10 @@ public class RemoveUnusedImports {
ParserFactory parserFactory = ParserFactory.instance(context);
JavacParser parser =
parserFactory.newParser(
- javaInput, /*keepDocComments=*/ true, /*keepEndPos=*/ true, /*keepLineMap=*/ true);
+ javaInput,
+ /* keepDocComments= */ true,
+ /* keepEndPos= */ true,
+ /* keepLineMap= */ true);
unit = parser.parseCompilationUnit();
unit.sourcefile = source;
Iterable<Diagnostic<? extends JavaFileObject>> errorDiagnostics =
@@ -290,9 +292,7 @@ public class RemoveUnusedImports {
}
private static String getSimpleName(JCImport importTree) {
- return importTree.getQualifiedIdentifier() instanceof JCIdent
- ? ((JCIdent) importTree.getQualifiedIdentifier()).getName().toString()
- : ((JCFieldAccess) importTree.getQualifiedIdentifier()).getIdentifier().toString();
+ return getQualifiedIdentifier(importTree).getIdentifier().toString();
}
private static boolean isUnused(
@@ -301,18 +301,15 @@ public class RemoveUnusedImports {
Multimap<String, Range<Integer>> usedInJavadoc,
JCImport importTree,
String simpleName) {
- String qualifier =
- ((JCFieldAccess) importTree.getQualifiedIdentifier()).getExpression().toString();
+ JCFieldAccess qualifiedIdentifier = getQualifiedIdentifier(importTree);
+ String qualifier = qualifiedIdentifier.getExpression().toString();
if (qualifier.equals("java.lang")) {
return true;
}
if (unit.getPackageName() != null && unit.getPackageName().toString().equals(qualifier)) {
return true;
}
- if (importTree.getQualifiedIdentifier() instanceof JCFieldAccess
- && ((JCFieldAccess) importTree.getQualifiedIdentifier())
- .getIdentifier()
- .contentEquals("*")) {
+ if (qualifiedIdentifier.getIdentifier().contentEquals("*")) {
return false;
}
@@ -325,6 +322,15 @@ public class RemoveUnusedImports {
return true;
}
+ private static JCFieldAccess getQualifiedIdentifier(JCImport importTree) {
+ // Use reflection because the return type is JCTree in some versions and JCFieldAccess in others
+ try {
+ return (JCFieldAccess) JCImport.class.getMethod("getQualifiedIdentifier").invoke(importTree);
+ } catch (ReflectiveOperationException e) {
+ throw new LinkageError(e.getMessage(), e);
+ }
+ }
+
/** Applies the replacements to the given source, and re-format any edited javadoc. */
private static String applyReplacements(String source, RangeMap<Integer, String> replacements) {
// save non-empty fixed ranges for reformatting after fixes are applied
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 c0f16e9..f241ae4 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;
@@ -96,7 +97,9 @@ public final class StringWrapper {
if (!expected.equals(actual)) {
throw new FormatterException(
String.format(
- "Something has gone terribly wrong. Please file a bug: "
+ "Something has gone terribly wrong. We planned to make the below formatting change,"
+ + " but have aborted because it would unexpectedly change the AST.\n"
+ + "Please file a bug: "
+ "https://github.com/google/google-java-format/issues/new"
+ "\n\n=== Actual: ===\n%s\n=== Expected: ===\n%s\n",
actual, expected));
@@ -120,6 +123,10 @@ public final class StringWrapper {
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)) {
@@ -396,7 +403,7 @@ public final class StringWrapper {
ParserFactory parserFactory = ParserFactory.instance(context);
JavacParser parser =
parserFactory.newParser(
- source, /*keepDocComments=*/ true, /*keepEndPos=*/ true, /*keepLineMap=*/ true);
+ source, /* keepDocComments= */ true, /* keepEndPos= */ true, /* keepLineMap= */ true);
unit = parser.parseCompilationUnit();
unit.sourcefile = sjfo;
Iterable<Diagnostic<? extends JavaFileObject>> errorDiagnostics =
diff --git a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
index 890687f..6818f4a 100644
--- a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java
+++ b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java
@@ -12,7 +12,7 @@
* the License.
*/
-package com.google.googlejavaformat.java.java14;
+package com.google.googlejavaformat.java.java17;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getOnlyElement;
@@ -25,9 +25,11 @@ import com.google.googlejavaformat.java.JavaInputAstVisitor;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.BindingPatternTree;
import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.CaseLabelTree;
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;
@@ -39,39 +41,23 @@ import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.TreeInfo;
-import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
import javax.lang.model.element.Name;
/**
- * Extends {@link JavaInputAstVisitor} with support for AST nodes that were added or modified for
- * Java 14.
+ * Extends {@link JavaInputAstVisitor} with support for AST nodes that were added or modified in
+ * Java 17.
*/
-public class Java14InputAstVisitor extends JavaInputAstVisitor {
- private static final Method COMPILATION_UNIT_TREE_GET_MODULE =
- maybeGetMethod(CompilationUnitTree.class, "getModule");
- private static final Method CLASS_TREE_GET_PERMITS_CLAUSE =
- maybeGetMethod(ClassTree.class, "getPermitsClause");
- private static final Method BINDING_PATTERN_TREE_GET_VARIABLE =
- maybeGetMethod(BindingPatternTree.class, "getVariable");
- private static final Method BINDING_PATTERN_TREE_GET_TYPE =
- maybeGetMethod(BindingPatternTree.class, "getType");
- private static final Method BINDING_PATTERN_TREE_GET_BINDING =
- maybeGetMethod(BindingPatternTree.class, "getBinding");
- private static final Method CASE_TREE_GET_LABELS = maybeGetMethod(CaseTree.class, "getLabels");
+public class Java17InputAstVisitor extends JavaInputAstVisitor {
- public Java14InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
+ public Java17InputAstVisitor(OpsBuilder builder, int indentMultiplier) {
super(builder, indentMultiplier);
}
@Override
protected void handleModule(boolean first, CompilationUnitTree node) {
- if (COMPILATION_UNIT_TREE_GET_MODULE == null) {
- // Java < 17, see https://bugs.openjdk.java.net/browse/JDK-8255464
- return;
- }
- ModuleTree module = (ModuleTree) invoke(COMPILATION_UNIT_TREE_GET_MODULE, node);
+ ModuleTree module = node.getModule();
if (module != null) {
if (!first) {
builder.blankLineWanted(BlankLineWanted.YES);
@@ -84,34 +70,20 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
@Override
protected List<? extends Tree> getPermitsClause(ClassTree node) {
- if (CLASS_TREE_GET_PERMITS_CLAUSE != null) {
- return (List<? extends Tree>) invoke(CLASS_TREE_GET_PERMITS_CLAUSE, node);
- } else {
- // Java < 15
- return super.getPermitsClause(node);
- }
+ return node.getPermitsClause();
}
@Override
public Void visitBindingPattern(BindingPatternTree node, Void unused) {
sync(node);
- if (BINDING_PATTERN_TREE_GET_VARIABLE != null) {
- VariableTree variableTree = (VariableTree) invoke(BINDING_PATTERN_TREE_GET_VARIABLE, node);
- visitBindingPattern(
- variableTree.getModifiers(), variableTree.getType(), variableTree.getName());
- } else if (BINDING_PATTERN_TREE_GET_TYPE != null && BINDING_PATTERN_TREE_GET_BINDING != null) {
- Tree type = (Tree) invoke(BINDING_PATTERN_TREE_GET_TYPE, node);
- Name name = (Name) invoke(BINDING_PATTERN_TREE_GET_BINDING, node);
- visitBindingPattern(/* modifiers= */ null, type, name);
- } else {
- throw new LinkageError(
- "BindingPatternTree must have either getVariable() or both getType() and getBinding(),"
- + " but does not");
- }
+ VariableTree variableTree = node.getVariable();
+ visitBindingPattern(
+ variableTree.getModifiers(), variableTree.getType(), variableTree.getName());
return null;
}
private void visitBindingPattern(ModifiersTree modifiers, Tree type, Name name) {
+ builder.open(plusFour);
if (modifiers != null) {
List<AnnotationTree> annotations =
visitModifiers(modifiers, Direction.HORIZONTAL, Optional.empty());
@@ -119,7 +91,12 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
}
scan(type, null);
builder.breakOp(" ");
- visit(name);
+ if (name.isEmpty()) {
+ token("_");
+ } else {
+ visit(name);
+ }
+ builder.close();
}
@Override
@@ -248,17 +225,14 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
sync(node);
markForPartialFormat();
builder.forcedBreak();
- List<? extends Tree> labels;
- boolean isDefault;
- if (CASE_TREE_GET_LABELS != null) {
- labels = (List<? extends Tree>) invoke(CASE_TREE_GET_LABELS, node);
- isDefault =
- labels.size() == 1
- && getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL");
- } else {
- labels = node.getExpressions();
- isDefault = labels.isEmpty();
- }
+ 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 {
@@ -276,6 +250,15 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
}
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(":");
@@ -287,8 +270,8 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
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(),
@@ -296,6 +279,7 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
AllowLeadingBlankLine.NO,
AllowTrailingBlankLine.NO);
} else {
+ builder.breakOp(" ");
scan(node.getBody(), null);
}
builder.guessToken(";");
@@ -303,22 +287,11 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor {
default:
throw new AssertionError(node.getCaseKind());
}
+ builder.close();
return null;
}
- private static Method maybeGetMethod(Class<?> c, String name) {
- try {
- return c.getMethod(name);
- } catch (ReflectiveOperationException e) {
- return null;
- }
- }
-
- private static Object invoke(Method m, Object target) {
- try {
- return m.invoke(target);
- } catch (ReflectiveOperationException e) {
- throw new LinkageError(e.getMessage(), e);
- }
+ 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 0000000..897d6ff
--- /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 2c65803..4d30840 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": "<init>",
+ "parameterTypes": ["com.google.googlejavaformat.OpsBuilder", "int"]
+ }
+ ]
+ },
+ {
+ "name": "com.google.googlejavaformat.java.java21.Java21InputAstVisitor",
+ "methods": [
+ {
+ "name": "<init>",
+ "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 61a4346..cf15ecb 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 class FormatterIntegrationTest {
String expectedOutput = outputs.get(fileName);
Optional<Integer> version =
VERSIONED_TESTS.inverse().get(fileName).stream().collect(toOptional());
- if (version.isPresent() && Runtime.version().feature() < version.get()) {
+ if (Runtime.version().feature() < version.orElse(Integer.MAX_VALUE)) {
continue;
}
testInputs.add(new Object[] {fileName, input, expectedOutput});
diff --git a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java
index 15e4522..3d41a07 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java
@@ -46,7 +46,7 @@ public class GoogleJavaFormatToolProviderTest {
int result = format.run(new PrintWriter(out, true), new PrintWriter(err, true), "--help");
- assertThat(result).isEqualTo(0);
+ assertThat(result).isNotEqualTo(0);
String usage = err.toString();
diff --git a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java
new file mode 100644
index 0000000..691bb22
--- /dev/null
+++ b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.ServiceLoader;
+import javax.tools.Tool;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link GoogleJavaFormatToolProvider}. */
+@RunWith(JUnit4.class)
+public class GoogleJavaFormatToolTest {
+
+ @Test
+ public void testUsageOutputAfterLoadingViaToolName() {
+ String name = "google-java-format";
+
+ assertThat(
+ ServiceLoader.load(Tool.class).stream()
+ .map(ServiceLoader.Provider::get)
+ .map(Tool::name))
+ .contains(name);
+
+ Tool format =
+ ServiceLoader.load(Tool.class).stream()
+ .filter(provider -> name.equals(provider.get().name()))
+ .findFirst()
+ .get()
+ .get();
+
+ InputStream in = new ByteArrayInputStream(new byte[0]);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+
+ int result = format.run(in, out, err, "--help");
+
+ assertThat(result).isNotEqualTo(0);
+
+ String usage = new String(err.toByteArray(), UTF_8);
+
+ // Check that doc links are included.
+ assertThat(usage).containsMatch("http.*/google-java-format");
+ assertThat(usage).contains("Usage: google-java-format");
+ }
+}
diff --git a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
index ac3eb39..42e12d8 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java
@@ -54,13 +54,12 @@ public class MainTest {
private static final ImmutableList<String> ADD_EXPORTS =
ImmutableList.of(
+ "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
- "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED");
+ "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED");
@Test
public void testUsageOutput() {
@@ -132,7 +131,7 @@ public class MainTest {
process.waitFor();
String err = new String(ByteStreams.toByteArray(process.getErrorStream()), UTF_8);
assertThat(err).contains("Usage: google-java-format");
- assertThat(process.exitValue()).isEqualTo(0);
+ assertThat(process.exitValue()).isEqualTo(2);
}
// end to end javadoc formatting test
@@ -613,4 +612,27 @@ public class MainTest {
assertThat(main.format("--skip-javadoc-formatting", "-")).isEqualTo(0);
assertThat(out.toString()).isEqualTo(joiner.join(input));
}
+
+ @Test
+ public void reorderModifiersOptionTest() throws Exception {
+ String[] input = {
+ "class Test {", //
+ " static public void main(String... args) {}",
+ "}",
+ "",
+ };
+ String[] fixed = {
+ "class Test {", //
+ " public static void main(String... args) {}",
+ "}",
+ "",
+ };
+ String source = joiner.join(input);
+ assertThat(new Formatter(JavaFormatterOptions.builder().build()).formatSource(source))
+ .isEqualTo(joiner.join(fixed));
+ assertThat(
+ new Formatter(JavaFormatterOptions.builder().reorderModifiers(false).build())
+ .formatSource(source))
+ .isEqualTo(source);
+ }
}
diff --git a/core/src/test/java/com/google/googlejavaformat/java/PartialFormattingTest.java b/core/src/test/java/com/google/googlejavaformat/java/PartialFormattingTest.java
index b1142b3..1750049 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/PartialFormattingTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/PartialFormattingTest.java
@@ -679,6 +679,7 @@ public final class PartialFormattingTest {
String input =
lines(
" package com.google.googlejavaformat.java;",
+ "",
"/*",
" * Copyright 2015 Google Inc.",
" *",
diff --git a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java
index 99e1b2f..f7be369 100644
--- a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java
+++ b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java
@@ -15,6 +15,7 @@
package com.google.googlejavaformat.java;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
import com.google.common.base.Joiner;
import org.junit.Test;
@@ -52,6 +53,26 @@ public class StringWrapperTest {
assertThat(StringWrapper.wrap(100, input, new Formatter())).isEqualTo(output);
}
+ @Test
+ public void textBlock() throws Exception {
+ assumeTrue(Runtime.version().feature() >= 15);
+ String input =
+ lines(
+ "package com.mypackage;",
+ "public class ReproBug {",
+ " private String myString;",
+ " private ReproBug() {",
+ " String str =",
+ " \"\"\"",
+ " "
+ + " {\"sourceEndpoint\":\"ri.something.1-1.object-internal.1\",\"targetEndpoint\":\"ri.some"
+ + "thing.1-1.object-internal.2\",\"typeId\":\"typeId\"}\"\"\";",
+ " myString = str;",
+ " }",
+ "}");
+ assertThat(StringWrapper.wrap(100, input, new Formatter())).isEqualTo(input);
+ }
+
private static String lines(String... line) {
return Joiner.on('\n').join(line) + '\n';
}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.input
index 7317f17..86e46d5 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.input
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.input
@@ -1,6 +1,6 @@
public class B20844369 {
private static final String ID_PATTERN =
- // TODO(user): add min/max lengths for the numbers here, e.g. android ID
+ // TODO(daw): add min/max lengths for the numbers here, e.g. android ID
"(?:(?<androidId>\\d+)\\+)?" // optional Android ID
+ "(?<type>\\d+)" // type
+ ":"
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.output
index 62f9721..982dc2b 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20844369.output
@@ -1,6 +1,6 @@
public class B20844369 {
private static final String ID_PATTERN =
- // TODO(user): add min/max lengths for the numbers here, e.g. android ID
+ // TODO(daw): add min/max lengths for the numbers here, e.g. android ID
"(?:(?<androidId>\\d+)\\+)?" // optional Android ID
+ "(?<type>\\d+)" // type
+ ":"
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B21283374.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B21283374.output
index f98a37b..777303e 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B21283374.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B21283374.output
@@ -14,41 +14,41 @@ class B21283374 {
{
f(
- /*flagA=*/ Boolean.TRUE,
- /*flagB=*/ Boolean.FALSE,
- /*flagC=*/ Boolean.FALSE,
- /*flagD=*/ Boolean.FALSE,
- /*flagE=*/ Boolean.FALSE,
- /*flagF=*/ Boolean.FALSE,
- /*flagG=*/ Boolean.FALSE,
- /*flagH=*/ Boolean.FALSE,
- /*flagI=*/ Boolean.FALSE,
- /*flagJ=*/ Boolean.FALSE,
- /*flagK=*/ Boolean.FALSE);
+ /* flagA= */ Boolean.TRUE,
+ /* flagB= */ Boolean.FALSE,
+ /* flagC= */ Boolean.FALSE,
+ /* flagD= */ Boolean.FALSE,
+ /* flagE= */ Boolean.FALSE,
+ /* flagF= */ Boolean.FALSE,
+ /* flagG= */ Boolean.FALSE,
+ /* flagH= */ Boolean.FALSE,
+ /* flagI= */ Boolean.FALSE,
+ /* flagJ= */ Boolean.FALSE,
+ /* flagK= */ Boolean.FALSE);
f(
- /*flagA=*/ Boolean.TRUE,
- /*flagB=*/ Boolean.FALSE,
- /*flagC=*/ Boolean.FALSE,
- /*flagD=*/ Boolean.FALSE,
- /*flagE=*/ Boolean.FALSE,
- /*flagF=*/ Boolean.FALSE,
- /*flagG=*/ Boolean.FALSE,
- /*flagH=*/ Boolean.FALSE,
- /*flagI=*/ Boolean.FALSE,
- /*flagJ=*/ Boolean.FALSE,
- /*flagK=*/ Boolean.FALSE);
+ /* flagA= */ Boolean.TRUE,
+ /* flagB= */ Boolean.FALSE,
+ /* flagC= */ Boolean.FALSE,
+ /* flagD= */ Boolean.FALSE,
+ /* flagE= */ Boolean.FALSE,
+ /* flagF= */ Boolean.FALSE,
+ /* flagG= */ Boolean.FALSE,
+ /* flagH= */ Boolean.FALSE,
+ /* flagI= */ Boolean.FALSE,
+ /* flagJ= */ Boolean.FALSE,
+ /* flagK= */ Boolean.FALSE);
- assertThat(foo.barAndBaz(/*paramName=*/ false, thingy)).isEqualTo(new Something(""));
- assertThat(foo.barAndBaz(/*paramName=*/ false, thingy)).isEqualTo(new Something(""));
- assertThat(foo.barAndBaz(/*paramName=*/ false, thingy)).isEqualTo(new Something(""));
+ assertThat(foo.barAndBaz(/* paramName= */ false, thingy)).isEqualTo(new Something(""));
+ assertThat(foo.barAndBaz(/* paramName= */ false, thingy)).isEqualTo(new Something(""));
+ assertThat(foo.barAndBaz(/* paramName= */ false, thingy)).isEqualTo(new Something(""));
- f(/*paramName=*/ false);
+ f(/* paramName= */ false);
assertThat__________________________________________________________(
- /*paramName=*/ false, thingy);
+ /* paramName= */ false, thingy);
assertThat__________________________________________________________(
- /*paramName=*/ false, thingy);
+ /* paramName= */ false, thingy);
f(
arg1, /* which arg is this attached to? */
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B26694550.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B26694550.output
index 945a40f..aedafb7 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B26694550.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B26694550.output
@@ -3,15 +3,15 @@ class B26694550 {
/* === not a param comment */
fffffffffffffffffffffffffffffff(
ImmutableList.copyOf(keys), /*&=*/
- /*keepGoing=*/ false,
+ /* keepGoing= */ false,
ggggggggggggggggggggggggggggggggggggggggggg);
fffffffffffffffffffffffffffffff(
ImmutableList.copyOf(keys),
- /*keepGoing=*/ false,
+ /* keepGoing= */ false,
ggggggggggggggggggggggggggggggggggggggggggg);
fffffffffffffffffffffffffffffff(
ImmutableList.copyOf(keys),
- /*foo_bar=*/ false,
+ /* foo_bar= */ false,
/*foo-bar=*/ false,
ggggggggggggggggggggggggggggggggggggggggggg);
}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B27246427.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B27246427.output
index b1e33e9..3d591f8 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B27246427.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B27246427.output
@@ -6,6 +6,7 @@ enum TrailingComment {
/** a */
Object a;
+
/** b */
Object b;
}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.input
deleted file mode 100644
index a38d10b..0000000
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.input
+++ /dev/null
@@ -1,7 +0,0 @@
-import a.A;;
-import b.B;
-
-class Test {
- A a;
- B b;
-}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.output
deleted file mode 100644
index 8a1db80..0000000
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B28788559.output
+++ /dev/null
@@ -1,8 +0,0 @@
-import a.A;
-;
-import b.B;
-
-class Test {
- A a;
- B b;
-}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.input
new file mode 100644
index 0000000..089a3f1
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.input
@@ -0,0 +1,23 @@
+class C {
+ @A(0x14)
+ int f(Object o) {
+ @A(0x40)
+ int local;
+ try (@A(0x41)
+ JarFile jarFile = new JarFile("hello.jar")) {
+ } catch (
+ @A(0x42)
+ IOException e) {
+ }
+ if (o instanceof @A(0x43) String) {}
+ new @A(0x44) ArrayList<>();
+ Supplier<List<?>> a = @A(0x45) ArrayList::new;
+ Supplier<List<?>> b = @A(0x46) ImmutableList::of;
+ String s = (@A(0x47) String) o;
+ List<?> xs = new ArrayList<@A(0x48) String>();
+ xs = ImmutableList.<@A(0x49) String>of();
+ Supplier<List<?>> c = ArrayList<@A(0x4A) String>::new;
+ Supplier<List<?>> d = ImmutableList::<@A(0x4B) String>of;
+ return 0;
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.output
new file mode 100644
index 0000000..089a3f1
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B308157568.output
@@ -0,0 +1,23 @@
+class C {
+ @A(0x14)
+ int f(Object o) {
+ @A(0x40)
+ int local;
+ try (@A(0x41)
+ JarFile jarFile = new JarFile("hello.jar")) {
+ } catch (
+ @A(0x42)
+ IOException e) {
+ }
+ if (o instanceof @A(0x43) String) {}
+ new @A(0x44) ArrayList<>();
+ Supplier<List<?>> a = @A(0x45) ArrayList::new;
+ Supplier<List<?>> b = @A(0x46) ImmutableList::of;
+ String s = (@A(0x47) String) o;
+ List<?> xs = new ArrayList<@A(0x48) String>();
+ xs = ImmutableList.<@A(0x49) String>of();
+ Supplier<List<?>> c = ArrayList<@A(0x4A) String>::new;
+ Supplier<List<?>> d = ImmutableList::<@A(0x4B) String>of;
+ return 0;
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.input
deleted file mode 100644
index be76390..0000000
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.input
+++ /dev/null
@@ -1,6 +0,0 @@
-package foo;;
-
-import com.google.second.Foo;
-import com.google.first.Bar;
-
-public class Blim {}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.output
deleted file mode 100644
index 025d237..0000000
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/CL240367479.output
+++ /dev/null
@@ -1,6 +0,0 @@
-package foo;
-;
-import com.google.second.Foo;
-import com.google.first.Bar;
-
-public class Blim {}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.input
index 9dc3426..d012d17 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.input
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.input
@@ -1,5 +1,12 @@
class Fields {
+ int a = 1;
+ int b = 1;
+
+ int c = 1;
+ /** Javadoc */
+ int d = 1;
+
int x = 1;
int y = 1;
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.output
index 376e8b6..81ebd2a 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Fields.output
@@ -1,5 +1,13 @@
class Fields {
+ int a = 1;
+ int b = 1;
+
+ int c = 1;
+
+ /** Javadoc */
+ int d = 1;
+
int x = 1;
int y = 1;
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.input
new file mode 100644
index 0000000..dfc8a4c
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.input
@@ -0,0 +1,19 @@
+class I880 {
+ public String f(int i) {
+ return switch (i) {
+ case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "looooooooooooooooooooooooooooooooooooooooong expression";
+ default -> "looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong expression";
+ };
+ }
+
+ public boolean test(int i) {
+ return switch (i) {
+ case 0 -> // zero
+ false;
+ case 1 -> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".length()
+ == 0;
+ default -> // otherwise
+ true;
+ };
+ }
+} \ No newline at end of file
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.output
new file mode 100644
index 0000000..f918665
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I880.output
@@ -0,0 +1,21 @@
+class I880 {
+ public String f(int i) {
+ return switch (i) {
+ case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ->
+ "looooooooooooooooooooooooooooooooooooooooong expression";
+ default ->
+ "looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong expression";
+ };
+ }
+
+ public boolean test(int i) {
+ return switch (i) {
+ case 0 -> // zero
+ false;
+ case 1 ->
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".length() == 0;
+ default -> // otherwise
+ true;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.input
new file mode 100644
index 0000000..0660079
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.input
@@ -0,0 +1,5 @@
+class I959 {
+ public void test() {
+ new File(".").listFiles((final var dir, final var name) -> true);
+ }
+} \ No newline at end of file
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.output
new file mode 100644
index 0000000..76a07f4
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I959.output
@@ -0,0 +1,5 @@
+class I959 {
+ public void test() {
+ new File(".").listFiles((final var dir, final var name) -> true);
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.input
new file mode 100644
index 0000000..bba0b72
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.input
@@ -0,0 +1,12 @@
+class Foo {
+ private static final int X = 42;
+ private static final String A = STR."\{X} = \{X}";
+ private static final String B = STR."";
+ private static final String C = STR."\{X}";
+ private static final String D = STR."\{X}\{X}";
+ private static final String E = STR."\{X}\{X}\{X}";
+ private static final String F = STR." \{X}";
+ private static final String G = STR."\{X} ";
+ private static final String H = STR."\{X} one long incredibly unbroken sentence moving from "+"topic to topic so that no-one had a chance to interrupt";
+ private static final String I = STR."\{X} \uD83D\uDCA9 ";
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.output
new file mode 100644
index 0000000..ff173fb
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I981.output
@@ -0,0 +1,14 @@
+class Foo {
+ private static final int X = 42;
+ private static final String A = STR."\{X} = \{X}";
+ private static final String B = STR."";
+ private static final String C = STR."\{X}";
+ private static final String D = STR."\{X}\{X}";
+ private static final String E = STR."\{X}\{X}\{X}";
+ private static final String F = STR." \{X}";
+ private static final String G = STR."\{X} ";
+ private static final String H =
+ STR."\{X} one long incredibly unbroken sentence moving from "
+ + "topic to topic so that no-one had a chance to interrupt";
+ private static final String I = STR."\{X} \uD83D\uDCA9 ";
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/M.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/M.output
index dbad1bb..d28d5dd 100644
--- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/M.output
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/M.output
@@ -36,8 +36,16 @@ class M {
/** JavaDoc. */
void methodName3(int x)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {}
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {}
/** JavaDoc. */
void methodName4(
@@ -114,8 +122,16 @@ class M {
int t,
int u,
int v)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {}
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {}
Pair<
Pair<Pair<Pair<T, T>, Pair<T, T>>, Pair<Pair<T, T>, Pair<T, T>>>,
@@ -135,8 +151,16 @@ class M {
Pair<Pair<Pair<T, T>, Pair<T, T>>, Pair<Pair<T, T>, Pair<T, T>>>,
Pair<Pair<Pair<T, T>, Pair<T, T>>, Pair<Pair<T, T>, Pair<T, T>>>>
methodName11(int x)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -225,8 +249,16 @@ class M {
int t,
int u,
int v)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -338,8 +370,16 @@ class M {
T30,
T31>
T methodName22(int x)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -518,8 +558,16 @@ class M {
int t,
int u,
int v)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5, Exception6,
- Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -640,8 +688,16 @@ class M {
Pair<Pair<Pair<T, T>, Pair<T, T>>, Pair<Pair<T, T>, Pair<T, T>>>,
Pair<Pair<Pair<T, T>, Pair<T, T>>, Pair<Pair<T, T>, Pair<T, T>>>>
methodName(int x)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5,
- Exception6, Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -829,8 +885,16 @@ class M {
int t,
int u,
int v)
- throws Exception0, Exception1, Exception2, Exception3, Exception4, Exception5,
- Exception6, Exception7, Exception8, Exception9 {
+ throws Exception0,
+ Exception1,
+ Exception2,
+ Exception3,
+ Exception4,
+ Exception5,
+ Exception6,
+ Exception7,
+ Exception8,
+ Exception9 {
return null;
}
@@ -1011,6 +1075,14 @@ class M {
ZZZZZZZZZZ z,
ZZZZZZZZZZ z,
ZZZZZZZZZZ z)
- throws EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE,
- EEEEEEEEEE, EEEEEEEEEE, EEEEEEEEEE {}
+ throws EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE,
+ EEEEEEEEEE {}
}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.input
new file mode 100644
index 0000000..decebe9
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.input
@@ -0,0 +1,29 @@
+package com.google.googlejavaformat.java.test;
+
+/** Tests for formatting of ParameterComments. */
+class Q {
+ static void f(int a) {
+ f(/*a=*/ 1);
+ f(
+ /* a= */ 1
+ );
+ }
+ static void g(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) {
+ g(
+ /*a=*/ 1,
+ /*b=*/ 1,
+ /*c=*/ 1,
+ /*d=*/ 1,
+ /*e=*/ 1,
+ /*f=*/ 1,
+ /*g=*/ 1,
+ /*h=*/ 1,
+ /*i=*/ 1,
+ /*j=*/ 1,
+ /*k=*/ 1);
+ g(/*a=*/ 1, /*b=*/ 1, /*c=*/ 1, /*d=*/ 1, /*e=*/ 1, /*f=*/ 1, /*g=*/ 1, /*h=*/ 1, /*i=*/ 1);
+ }
+ static void h(Object... xs) {
+ h(/*xs...=*/ null);
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.output
new file mode 100644
index 0000000..d26ca11
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/ParameterComment.output
@@ -0,0 +1,38 @@
+package com.google.googlejavaformat.java.test;
+
+/** Tests for formatting of ParameterComments. */
+class Q {
+ static void f(int a) {
+ f(/* a= */ 1);
+ f(/* a= */ 1);
+ }
+
+ static void g(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k) {
+ g(
+ /* a= */ 1,
+ /* b= */ 1,
+ /* c= */ 1,
+ /* d= */ 1,
+ /* e= */ 1,
+ /* f= */ 1,
+ /* g= */ 1,
+ /* h= */ 1,
+ /* i= */ 1,
+ /* j= */ 1,
+ /* k= */ 1);
+ g(
+ /* a= */ 1,
+ /* b= */ 1,
+ /* c= */ 1,
+ /* d= */ 1,
+ /* e= */ 1,
+ /* f= */ 1,
+ /* g= */ 1,
+ /* h= */ 1,
+ /* i= */ 1);
+ }
+
+ static void h(Object... xs) {
+ h(/* xs...= */ null);
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.input
new file mode 100644
index 0000000..54e22a7
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.input
@@ -0,0 +1,7 @@
+class SwitchDouble {
+ void x(Object o) {
+ switch (o) {
+ case null, default:
+ }
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.output
new file mode 100644
index 0000000..54e22a7
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchDouble.output
@@ -0,0 +1,7 @@
+class SwitchDouble {
+ void x(Object o) {
+ switch (o) {
+ case null, default:
+ }
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input
new file mode 100644
index 0000000..25df580
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.input
@@ -0,0 +1,9 @@
+class SwitchGuardClause {
+ boolean test(Object x) {
+ return switch (x) {
+ case String s when s.length() < 5 -> true;
+ case Integer i -> false;
+ default -> true;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output
new file mode 100644
index 0000000..25df580
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchGuardClause.output
@@ -0,0 +1,9 @@
+class SwitchGuardClause {
+ boolean test(Object x) {
+ return switch (x) {
+ case String s when s.length() < 5 -> true;
+ case Integer i -> false;
+ default -> true;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.input
new file mode 100644
index 0000000..2f4fb35
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.input
@@ -0,0 +1,21 @@
+record SwitchRecord(int i) {
+ int x(Object o) {
+ return switch (o) {
+ case SwitchRecord(int i) -> i;
+ default -> 0;
+ };
+ }
+ int f(Object o) {
+ return switch (o) {
+ case SwitchRecord(int one, int two, int three, int four, int five, int six, int seven, int eight, int nine) -> nine;
+ default -> 0;
+ };
+ }
+ int g(Object o) {
+ return switch (o) {
+ case SwitchRecord(int one, int two, int three, int four, int five, int six, int seven, int eight, int nine) ->
+ 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.");
+ default -> 0;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.output
new file mode 100644
index 0000000..89d212f
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchRecord.output
@@ -0,0 +1,46 @@
+record SwitchRecord(int i) {
+ int x(Object o) {
+ return switch (o) {
+ case SwitchRecord(int i) -> i;
+ default -> 0;
+ };
+ }
+
+ int f(Object o) {
+ return switch (o) {
+ case SwitchRecord(
+ int one,
+ int two,
+ int three,
+ int four,
+ int five,
+ int six,
+ int seven,
+ int eight,
+ int nine) ->
+ nine;
+ default -> 0;
+ };
+ }
+
+ int g(Object o) {
+ return switch (o) {
+ case SwitchRecord(
+ int one,
+ int two,
+ int three,
+ int four,
+ int five,
+ int six,
+ int seven,
+ int eight,
+ int nine) ->
+ 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.");
+ default -> 0;
+ };
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.input
new file mode 100644
index 0000000..8d611d2
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.input
@@ -0,0 +1,8 @@
+public class SwitchUnderscore {
+ void x(Object o) {
+ switch (o) {
+ case String _:
+ default:
+ }
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.output
new file mode 100644
index 0000000..8d611d2
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/SwitchUnderscore.output
@@ -0,0 +1,8 @@
+public class SwitchUnderscore {
+ void x(Object o) {
+ switch (o) {
+ case String _:
+ default:
+ }
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.input
new file mode 100644
index 0000000..6c5efd1
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.input
@@ -0,0 +1,44 @@
+class Unnamed {
+ {
+ int acc = 0;
+ for (Order _ : orders) {
+ if (acc < LIMIT) {
+ acc++;
+ }
+ }
+
+ for (int i = 0, _ = sideEffect(); i < 10; i++) { }
+
+ Queue<Integer> q = null;
+ while (q.size() >= 3) {
+ var x = q.remove();
+ var y = q.remove();
+ var _ = q.remove();
+ new Point(x, y);
+ }
+
+ while (q.size() >= 3) {
+ var x = q.remove();
+ var _ = q.remove();
+ var _ = q.remove();
+ new Point(x, 0) ;
+ }
+
+ String s = null;
+ try {
+ int i = Integer.parseInt(s);
+ } catch (NumberFormatException _) {
+ System.out.println("Bad number: " + s);
+ }
+
+ try { doSomething(); }
+ catch (Exception _) { doSomething(); }
+ catch (Throwable _) { doSomething(); }
+
+ try (var _ = ScopedContext.acquire()) {
+ doSomething();
+ }
+
+ stream.collect(Collectors.toMap(String::toUpperCase, _ -> "NODATA"));
+ }
+}
diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.output
new file mode 100644
index 0000000..84d8f87
--- /dev/null
+++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/Unnamed.output
@@ -0,0 +1,48 @@
+class Unnamed {
+ {
+ int acc = 0;
+ for (Order _ : orders) {
+ if (acc < LIMIT) {
+ acc++;
+ }
+ }
+
+ for (int i = 0, _ = sideEffect(); i < 10; i++) {}
+
+ Queue<Integer> q = null;
+ while (q.size() >= 3) {
+ var x = q.remove();
+ var y = q.remove();
+ var _ = q.remove();
+ new Point(x, y);
+ }
+
+ while (q.size() >= 3) {
+ var x = q.remove();
+ var _ = q.remove();
+ var _ = q.remove();
+ new Point(x, 0);
+ }
+
+ String s = null;
+ try {
+ int i = Integer.parseInt(s);
+ } catch (NumberFormatException _) {
+ System.out.println("Bad number: " + s);
+ }
+
+ try {
+ doSomething();
+ } catch (Exception _) {
+ doSomething();
+ } catch (Throwable _) {
+ doSomething();
+ }
+
+ try (var _ = ScopedContext.acquire()) {
+ doSomething();
+ }
+
+ stream.collect(Collectors.toMap(String::toUpperCase, _ -> "NODATA"));
+ }
+}