diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14d29b090..6e73bdb0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,13 @@ name: CI -on: [ push, pull_request ] +on: + push: + branches: + - master + pull_request: + branches: + - master jobs: test: @@ -23,23 +29,27 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest ] - java: [ 15, 11 ] + java: [ 16, 14, 11 ] experimental: [ false ] include: # Only test on macos and windows with a single recent JDK to avoid a # combinatorial explosion of test configurations. - os: macos-latest - java: 15 + java: 16 experimental: false - os: windows-latest - java: 15 + java: 16 experimental: false - os: ubuntu-latest - java: 16-ea + java: 17-ea experimental: true runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} steps: + - name: Cancel previous + uses: styfle/cancel-workflow-action@0.8.0 + with: + access_token: ${{ github.token }} - name: 'Check out repository' uses: actions/checkout@v2 - name: 'Cache local Maven repository' diff --git a/README.md b/README.md index 6f7d5c654..5bbf5e5a1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ and run it with: ``` -java -jar /path/to/google-java-format-1.9-all-deps.jar [files...] +java -jar /path/to/google-java-format-1.10.0-all-deps.jar [files...] ``` The formatter can act on whole files, on limited lines (`--lines`), on specific @@ -27,6 +27,21 @@ To reformat changed lines in a specific patch, use formatting. This is a deliberate design decision to unify our code formatting on a single format.* +#### JDK 16 + +The following flags are required when running on JDK 16, due to +[JEP 396: Strongly Encapsulate JDK Internals by Default](https://openjdk.java.net/jeps/396): + +``` +java \ + --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.file=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 \ + -jar google-java-format-1.10.0-all-deps.jar [files...] +``` + ### IntelliJ, Android Studio, and other JetBrains IDEs A @@ -98,7 +113,7 @@ configuration. com.google.googlejavaformat google-java-format - 1.9 + 1.10.0 ``` @@ -106,7 +121,7 @@ configuration. ```groovy dependencies { - compile 'com.google.googlejavaformat:google-java-format:1.9' + compile 'com.google.googlejavaformat:google-java-format:1.10.0' } ``` diff --git a/core/pom.xml b/core/pom.xml index e2d015316..faa94d627 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ com.google.googlejavaformat google-java-format-parent - 1.10-SNAPSHOT + HEAD-SNAPSHOT google-java-format diff --git a/core/src/main/java/com/google/googlejavaformat/Input.java b/core/src/main/java/com/google/googlejavaformat/Input.java index 9e17c2bf6..fb71e047c 100644 --- a/core/src/main/java/com/google/googlejavaformat/Input.java +++ b/core/src/main/java/com/google/googlejavaformat/Input.java @@ -114,14 +114,14 @@ public interface Token { /** * Get the number of toks. * - * @return the number of toks, including the EOF tok + * @return the number of toks, excluding the EOF tok */ public abstract int getkN(); /** * Get the Token by index. * - * @param k the token index + * @param k the Tok index */ public abstract Token getToken(int k); 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 999c8fb7f..d07d003ef 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInput.java @@ -594,7 +594,7 @@ Range characterRangeToTokenRange(int offset, int length) throws Formatt /** * Get the number of toks. * - * @return the number of toks, including the EOF tok + * @return the number of toks, excluding the EOF tok */ @Override public int getkN() { @@ -604,7 +604,7 @@ public int getkN() { /** * Get the Token by index. * - * @param k the token index + * @param k the Tok index */ @Override public Token getToken(int k) { 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 05a42df7b..89ec1f86e 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -1599,11 +1599,7 @@ public Void visitMemberSelect(MemberSelectTree node, Void unused) { public Void visitLiteral(LiteralTree node, Void unused) { sync(node); String sourceForNode = getSourceForNode(node, getCurrentPath()); - // A negative numeric literal -n is usually represented as unary minus on n, - // but that doesn't work for integer or long MIN_VALUE. The parser works - // around that by representing it directly as a signed literal (with no - // unary minus), but the lexer still expects two tokens. - if (sourceForNode.startsWith("-")) { + if (isUnaryMinusLiteral(sourceForNode)) { token("-"); sourceForNode = sourceForNode.substring(1).trim(); } @@ -1611,6 +1607,14 @@ public Void visitLiteral(LiteralTree node, Void unused) { return null; } + // A negative numeric literal -n is usually represented as unary minus on n, + // but that doesn't work for integer or long MIN_VALUE. The parser works + // around that by representing it directly as a signed literal (with no + // unary minus), but the lexer still expects two tokens. + private static boolean isUnaryMinusLiteral(String literalTreeSource) { + return literalTreeSource.startsWith("-"); + } + private void visitPackage( ExpressionTree packageName, List packageAnnotations) { if (!packageAnnotations.isEmpty()) { @@ -1696,10 +1700,10 @@ private boolean ambiguousUnaryOperator(UnaryTree node, String operatorName) { default: return false; } - if (!(node.getExpression() instanceof UnaryTree)) { + JCTree.Tag tag = unaryTag(node.getExpression()); + if (tag == null) { return false; } - JCTree.Tag tag = ((JCTree) node.getExpression()).getTag(); if (tag.isPostUnaryOp()) { return false; } @@ -1709,6 +1713,17 @@ private boolean ambiguousUnaryOperator(UnaryTree node, String operatorName) { return true; } + private JCTree.Tag unaryTag(ExpressionTree expression) { + if (expression instanceof UnaryTree) { + return ((JCTree) expression).getTag(); + } + if (expression instanceof LiteralTree + && isUnaryMinusLiteral(getSourceForNode(expression, getCurrentPath()))) { + return JCTree.Tag.MINUS; + } + return null; + } + @Override public Void visitPrimitiveType(PrimitiveTypeTree node, Void unused) { sync(node); 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 063843622..c0f16e9b5 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -239,9 +239,10 @@ static int hasEscapedNewlineAt(String input, int idx) { * @param separator the line separator * @param columnLimit the number of columns to wrap at * @param startColumn the column position of the beginning of the original text - * @param trailing extra space to leave after the last line - * @param components the text to reflow - * @param first0 true if the text includes the beginning of its enclosing concat chain, i.e. a + * @param trailing extra space to leave after the last line, to accommodate a ; or ) + * @param components the text to reflow. This is a list of “words” of a single literal. Its first + * and last quotes have been stripped + * @param first0 true if the text includes the beginning of its enclosing concat chain */ private static String reflow( String separator, @@ -251,7 +252,7 @@ private static String reflow( ImmutableList components, boolean first0) { // We have space between the start column and the limit to output the first line. - // Reserve two spaces for the quotes. + // Reserve two spaces for the start and end quotes. int width = columnLimit - startColumn - 2; Deque input = new ArrayDeque<>(components); List lines = new ArrayList<>(); @@ -259,10 +260,13 @@ private static String reflow( while (!input.isEmpty()) { int length = 0; List line = new ArrayList<>(); + // If we know this is going to be the last line, then remove a bit of width to account for the + // trailing characters. if (input.stream().mapToInt(String::length).sum() <= width) { + // This isn’t quite optimal, but arguably good enough. See b/179561701 width -= trailing; } - while (!input.isEmpty() && (length <= 4 || (length + input.peekFirst().length()) < width)) { + while (!input.isEmpty() && (length <= 4 || (length + input.peekFirst().length()) <= width)) { String text = input.removeFirst(); line.add(text); length += text.length(); diff --git a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java index 7885bd754..097029bb9 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java @@ -15,7 +15,6 @@ package com.google.googlejavaformat.java.java14; import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.collect.MoreCollectors.toOptional; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -28,13 +27,13 @@ import com.sun.source.tree.ClassTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.InstanceOfTree; +import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.SwitchExpressionTree; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; import com.sun.source.tree.YieldTree; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeInfo; import java.util.List; @@ -57,12 +56,13 @@ public Void visitBindingPattern(BindingPatternTree node, Void unused) { try { VariableTree variableTree = (VariableTree) BindingPatternTree.class.getMethod("getVariable").invoke(node); - visitBindingPattern(variableTree.getType(), variableTree.getName()); + visitBindingPattern( + variableTree.getModifiers(), variableTree.getType(), variableTree.getName()); } catch (ReflectiveOperationException e1) { try { Tree type = (Tree) BindingPatternTree.class.getMethod("getType").invoke(node); - Name name = (Name) BindingPatternTree.class.getMethod("getName").invoke(node); - visitBindingPattern(type, name); + Name name = (Name) BindingPatternTree.class.getMethod("getBinding").invoke(node); + visitBindingPattern(/* modifiers= */ null, type, name); } catch (ReflectiveOperationException e2) { e2.addSuppressed(e1); throw new LinkageError(e2.getMessage(), e2); @@ -71,7 +71,10 @@ public Void visitBindingPattern(BindingPatternTree node, Void unused) { return null; } - private void visitBindingPattern(Tree type, Name name) { + private void visitBindingPattern(ModifiersTree modifiers, Tree type, Name name) { + if (modifiers != null) { + builder.addAll(visitModifiers(modifiers, Direction.HORIZONTAL, Optional.empty())); + } scan(type, null); builder.breakOp(" "); visit(name); @@ -137,10 +140,7 @@ public void visitRecordDeclaration(ClassTree node) { if (!node.getTypeParameters().isEmpty()) { typeParametersRest(node.getTypeParameters(), hasSuperInterfaceTypes ? plusFour : ZERO); } - ImmutableList parameters = - compactRecordConstructor(node) - .map(m -> ImmutableList.copyOf(m.getParameters())) - .orElseGet(() -> recordVariables(node)); + ImmutableList parameters = recordVariables(node); token("("); if (!parameters.isEmpty()) { // Break before args. @@ -179,14 +179,6 @@ public void visitRecordDeclaration(ClassTree node) { dropEmptyDeclarations(); } - private static Optional compactRecordConstructor(ClassTree node) { - return node.getMembers().stream() - .filter(JCMethodDecl.class::isInstance) - .map(JCMethodDecl.class::cast) - .filter(m -> (m.mods.flags & COMPACT_RECORD_CONSTRUCTOR) == COMPACT_RECORD_CONSTRUCTOR) - .collect(toOptional()); - } - private static ImmutableList recordVariables(ClassTree node) { return node.getMembers().stream() .filter(JCVariableDecl.class::isInstance) 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 44ba63925..31d59f171 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java @@ -48,7 +48,9 @@ public class FormatterIntegrationTest { private static final ImmutableSet JAVA14_TESTS = - ImmutableSet.of("I477", "Records", "RSLs", "Var", "ExpressionSwitch"); + ImmutableSet.of("I477", "Records", "RSLs", "Var", "ExpressionSwitch", "I574", "I594"); + + private static final ImmutableSet JAVA16_TESTS = ImmutableSet.of("I588"); @Parameters(name = "{index}: {0}") public static Iterable data() throws IOException { @@ -76,7 +78,7 @@ public static Iterable data() throws IOException { case "output": outputs.put(baseName, contents); break; - default: + default: // fall out } } } @@ -90,6 +92,9 @@ public static Iterable data() throws IOException { if (JAVA14_TESTS.contains(fileName) && getMajor() < 14) { continue; } + if (JAVA16_TESTS.contains(fileName) && getMajor() < 16) { + continue; + } testInputs.add(new Object[] {fileName, input, expectedOutput}); } return testInputs; @@ -125,7 +130,9 @@ public FormatterIntegrationTest(String name, String input, String expected) { @Test public void format() { try { - String output = new Formatter().formatSource(input); + Formatter formatter = new Formatter(); + String output = formatter.formatSource(input); + output = StringWrapper.wrap(output, formatter); assertEquals("bad output for " + name, expected, output); } catch (FormatterException e) { fail(String.format("Formatter crashed on %s: %s", name, e.getMessage())); 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 fa23486fd..575153efe 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/MainTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/MainTest.java @@ -52,6 +52,16 @@ public class MainTest { // PrintWriter instances used below are hard-coded to use system-default line separator. private final Joiner joiner = Joiner.on(System.lineSeparator()); + private static final ImmutableList ADD_EXPORTS = + ImmutableList.of( + "--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"); + @Test public void testUsageOutput() { StringWriter out = new StringWriter(); @@ -109,11 +119,13 @@ public void preserveOriginalFile() throws Exception { public void testMain() throws Exception { Process process = new ProcessBuilder( - ImmutableList.of( - Paths.get(JAVA_HOME.value()).resolve("bin/java").toString(), - "-cp", - JAVA_CLASS_PATH.value(), - Main.class.getName())) + ImmutableList.builder() + .add(Paths.get(JAVA_HOME.value()).resolve("bin/java").toString()) + .addAll(ADD_EXPORTS) + .add("-cp") + .add(JAVA_CLASS_PATH.value()) + .add(Main.class.getName()) + .build()) .redirectError(Redirect.PIPE) .redirectOutput(Redirect.PIPE) .start(); @@ -435,14 +447,16 @@ public void exitIfChangedStdin() throws Exception { Files.write(path, "class Test {\n}\n".getBytes(UTF_8)); Process process = new ProcessBuilder( - ImmutableList.of( - Paths.get(JAVA_HOME.value()).resolve("bin/java").toString(), - "-cp", - JAVA_CLASS_PATH.value(), - Main.class.getName(), - "-n", - "--set-exit-if-changed", - "-")) + ImmutableList.builder() + .add(Paths.get(JAVA_HOME.value()).resolve("bin/java").toString()) + .addAll(ADD_EXPORTS) + .add("-cp") + .add(JAVA_CLASS_PATH.value()) + .add(Main.class.getName()) + .add("-n") + .add("--set-exit-if-changed") + .add("-") + .build()) .redirectInput(path.toFile()) .redirectError(Redirect.PIPE) .redirectOutput(Redirect.PIPE) @@ -461,14 +475,16 @@ public void exitIfChangedFiles() throws Exception { Files.write(path, "class Test {\n}\n".getBytes(UTF_8)); Process process = new ProcessBuilder( - ImmutableList.of( - Paths.get(JAVA_HOME.value()).resolve("bin/java").toString(), - "-cp", - JAVA_CLASS_PATH.value(), - Main.class.getName(), - "-n", - "--set-exit-if-changed", - path.toAbsolutePath().toString())) + ImmutableList.builder() + .add(Paths.get(JAVA_HOME.value()).resolve("bin/java").toString()) + .addAll(ADD_EXPORTS) + .add("-cp") + .add(JAVA_CLASS_PATH.value()) + .add(Main.class.getName()) + .add("-n") + .add("--set-exit-if-changed") + .add(path.toAbsolutePath().toString()) + .build()) .redirectError(Redirect.PIPE) .redirectOutput(Redirect.PIPE) .start(); @@ -525,8 +541,8 @@ public void reflowLongStrings() throws Exception { "class T {", " String s =", " \"one long incredibly unbroken sentence moving from topic to topic so that no one had" - + " a\"", - " + \" chance to interrupt\";", + + " a chance\"", + " + \" to interrupt\";", "}", "", }; diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.input new file mode 100644 index 000000000..e3e849399 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.input @@ -0,0 +1,8 @@ +class B173808510 { + // b/173808510 + @FlagSpec( + name = "myFlag", + help = + "areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyloongword word1 word2") + Flag dummy = null; +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.output new file mode 100644 index 000000000..45a939efb --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B173808510.output @@ -0,0 +1,9 @@ +class B173808510 { + // b/173808510 + @FlagSpec( + name = "myFlag", + help = + "areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyloongword word1" + + " word2") + Flag dummy = null; +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.input new file mode 100644 index 000000000..7c220d519 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.input @@ -0,0 +1,4 @@ +class B183431894 { + int a = - -1; + int d = + +1; +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.output new file mode 100644 index 000000000..7c220d519 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B183431894.output @@ -0,0 +1,4 @@ +class B183431894 { + int a = - -1; + int d = + +1; +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.input index 30c232b56..9408235da 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.input +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.input @@ -5,7 +5,7 @@ class Test { if (!metadata.ignoreOutputTransformations() && Producers.isListenableFutureMapKey(outputKey)) { ImmutableList> nodes = createMapNodes((ProducerNode) node); - checkCollectionNodesAgainstWhitelist(nodes, whitelist); + checkCollectionNodesAgainstAllowlist(nodes, allowlist); return nodes; } else if (!metadata.ignoreOutputTransformations() diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.output index 950f4eb0a..aeb36b82c 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.output +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20535125.output @@ -4,7 +4,7 @@ class Test { void m() { if (!metadata.ignoreOutputTransformations() && Producers.isListenableFutureMapKey(outputKey)) { ImmutableList> nodes = createMapNodes((ProducerNode) node); - checkCollectionNodesAgainstWhitelist(nodes, whitelist); + checkCollectionNodesAgainstAllowlist(nodes, allowlist); return nodes; } else if (!metadata.ignoreOutputTransformations() diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.input index 957c2df57..de746bb77 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.input +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.input @@ -1,8 +1,8 @@ class B20701054 { void m() { ImmutableList x = ImmutableList.builder().add(1).build(); - OptionalBinder.newOptionalBinder(binder(), InputWhitelist.class).setBinding().to( - AllInputWhitelist.class); + OptionalBinder.newOptionalBinder(binder(), InputAllowlist.class).setBinding().to( + AllInputAllowlist.class); Foo z = Foo.INSTANCE.field; Foo z = Foo.INSTANCE.field.field; diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.output index 7ce6fdad7..2fd9a9af7 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.output +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B20701054.output @@ -1,9 +1,9 @@ class B20701054 { void m() { ImmutableList x = ImmutableList.builder().add(1).build(); - OptionalBinder.newOptionalBinder(binder(), InputWhitelist.class) + OptionalBinder.newOptionalBinder(binder(), InputAllowlist.class) .setBinding() - .to(AllInputWhitelist.class); + .to(AllInputAllowlist.class); Foo z = Foo.INSTANCE.field; Foo z = Foo.INSTANCE.field.field; diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.input new file mode 100644 index 000000000..27d23d040 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.input @@ -0,0 +1,6 @@ +public record Record(@NotNull Object o) { + + public Record { + this.o = o; + } +} \ No newline at end of file diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.output new file mode 100644 index 000000000..b0deb2d10 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I574.output @@ -0,0 +1,6 @@ +public record Record(@NotNull Object o) { + + public Record { + this.o = o; + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.input new file mode 100644 index 000000000..9c8f992ea --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.input @@ -0,0 +1,8 @@ +class T { + int f(Object x) { + if (x instanceof final Integer i) { + return i; + } + return -1; + } +} \ No newline at end of file diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.output new file mode 100644 index 000000000..37ff2f50d --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I588.output @@ -0,0 +1,8 @@ +class T { + int f(Object x) { + if (x instanceof final Integer i) { + return i; + } + return -1; + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.input new file mode 100644 index 000000000..98f667e39 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.input @@ -0,0 +1,7 @@ +public class I594 { + public void thisIsNotFormattedCorrectly(Object something){ + if(something instanceof String somethingAsString){ + return; + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.output new file mode 100644 index 000000000..7c519a2d9 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I594.output @@ -0,0 +1,7 @@ +public class I594 { + public void thisIsNotFormattedCorrectly(Object something) { + if (something instanceof String somethingAsString) { + return; + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.input new file mode 100644 index 000000000..2aa4de330 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.input @@ -0,0 +1,44 @@ +class LiteralReflow { + static class TestLineBreak { + String doesNotBreakAt100 = "A very long long long long long long long long long loong sentence"; + String breaksAt101 = "A very long long long long long long long long long long loooong sentence"; + } + + static class TestReflowLimit { + String doesNotReflowAt100 = + "A very long long long long long long long long long long long long long looooong sentence"; + String reflowsWhenLongerThan100 = + "A very long long long long long long long long long long long long long long long sentence"; + } + + static class TestReflowLocation { + String accommodatesWordsUpTo100 = + "A very long long long long long long long long long long long long long long long looooong sentence"; + String breaksBeforeWordsReach101 = + "A very long long long long long long long long long long long long long long long loooooong sentence"; + } + + static class Test2LineReflowLimit { + String doesNotReflowEitherLinesAt100 = + "A very long long long long long long long long long long long long long looooong sentence. And a second very long long long long long long long long long long loong sentence"; + String reflowsLastLineAt101 = + "A very long long long long long long long long long long long long long looooong sentence. And a second very long long long long long long long long long long looong sentence"; + } + + static class TestWithTrailingCharacters { + String fitsLastLineUpTo100WithTrailingCharacters = + f( + f( + "A very long long long long long long long long long long long long loong sentence. And a second very long long long long long long long long loong sentence")); + String reflowsLastLineToAccommodateTrailingCharacters = + f( + f( + "A very long long long long long long long long long long long long loong sentence. And a second very long long long long long long long long looong sentence")); + // Tests an off-by-one issue, but see b/179561701 for a similar issue that is not yet fixed + String doesNotOverTriggerLastLineReflow = + f( + f( + "A very long long long long long long long long long long long long loong sentence." + + " And a second very loong sentence with trailing a a a a a a a a a a a a a a a")); + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.output new file mode 100644 index 000000000..50ed7bda1 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/LiteralReflow.output @@ -0,0 +1,55 @@ +class LiteralReflow { + static class TestLineBreak { + String doesNotBreakAt100 = "A very long long long long long long long long long loong sentence"; + String breaksAt101 = + "A very long long long long long long long long long long loooong sentence"; + } + + static class TestReflowLimit { + String doesNotReflowAt100 = + "A very long long long long long long long long long long long long long looooong sentence"; + String reflowsWhenLongerThan100 = + "A very long long long long long long long long long long long long long long long" + + " sentence"; + } + + static class TestReflowLocation { + String accommodatesWordsUpTo100 = + "A very long long long long long long long long long long long long long long long looooong" + + " sentence"; + String breaksBeforeWordsReach101 = + "A very long long long long long long long long long long long long long long long" + + " loooooong sentence"; + } + + static class Test2LineReflowLimit { + String doesNotReflowEitherLinesAt100 = + "A very long long long long long long long long long long long long long looooong sentence." + + " And a second very long long long long long long long long long long loong sentence"; + String reflowsLastLineAt101 = + "A very long long long long long long long long long long long long long looooong sentence." + + " And a second very long long long long long long long long long long looong" + + " sentence"; + } + + static class TestWithTrailingCharacters { + String fitsLastLineUpTo100WithTrailingCharacters = + f( + f( + "A very long long long long long long long long long long long long loong sentence." + + " And a second very long long long long long long long long loong sentence")); + String reflowsLastLineToAccommodateTrailingCharacters = + f( + f( + "A very long long long long long long long long long long long long loong sentence." + + " And a second very long long long long long long long long looong" + + " sentence")); + // Tests an off-by-one issue, but see b/179561701 for a similar issue that is not yet fixed + String doesNotOverTriggerLastLineReflow = + f( + f( + "A very long long long long long long long long long long long long loong sentence." + + " And a second very loong sentence with trailing a a a a a a a a a a a a a a" + + " a")); + } +} diff --git a/idea_plugin/build.gradle b/idea_plugin/build.gradle index 6ec1c210d..3d807af01 100644 --- a/idea_plugin/build.gradle +++ b/idea_plugin/build.gradle @@ -15,7 +15,7 @@ */ plugins { - id "org.jetbrains.intellij" version "0.4.22" + id "org.jetbrains.intellij" version "0.7.2" } repositories { @@ -23,7 +23,7 @@ repositories { } ext { - googleJavaFormatVersion = '1.9' + googleJavaFormatVersion = '1.10.0' } apply plugin: 'org.jetbrains.intellij' @@ -31,13 +31,13 @@ apply plugin: 'java' intellij { pluginName = "google-java-format" - version = "2020.2.2" + version = "211.6693.65-EAP-SNAPSHOT" } patchPluginXml { pluginDescription = "Formats source code using the google-java-format tool. This version of " + "the plugin uses version ${googleJavaFormatVersion} of the tool." - version = "${googleJavaFormatVersion}.0.0" + version = "${googleJavaFormatVersion}.0" sinceBuild = '201' untilBuild = '' } diff --git a/idea_plugin/resources/META-INF/plugin.xml b/idea_plugin/resources/META-INF/plugin.xml index 5996dba68..b089ad603 100644 --- a/idea_plugin/resources/META-INF/plugin.xml +++ b/idea_plugin/resources/META-INF/plugin.xml @@ -14,7 +14,7 @@ limitations under the License. --> - + google-java-format google-java-format @@ -28,12 +28,14 @@ +
1.10.0.0
+
Updated to use google-java-format 1.10.
1.9.0.0
-
Updated to use google-java-format 1.9.
+
Updated to use google-java-format 1.9.
1.8.0.1
-
Fixed support for 2020.2 IDEs.
+
Fixed support for 2020.2 IDEs.
1.8.0.0
-
Updated to use google-java-format 1.8.
+
Updated to use google-java-format 1.8.
1.7.0.5
Added a version for 2020.1+ IDEs.
1.7.0.4
diff --git a/idea_plugin/src/com/google/googlejavaformat/intellij/CodeStyleManagerDecorator.java b/idea_plugin/src/com/google/googlejavaformat/intellij/CodeStyleManagerDecorator.java index c70ba1751..fc335ad63 100644 --- a/idea_plugin/src/com/google/googlejavaformat/intellij/CodeStyleManagerDecorator.java +++ b/idea_plugin/src/com/google/googlejavaformat/intellij/CodeStyleManagerDecorator.java @@ -89,7 +89,7 @@ public void reformatText(PsiFile file, int startOffset, int endOffset) } @Override - public void reformatText(PsiFile file, Collection ranges) + public void reformatText(PsiFile file, Collection ranges) throws IncorrectOperationException { delegate.reformatText(file, ranges); } @@ -101,7 +101,7 @@ public void reformatTextWithContext(PsiFile psiFile, ChangedRangesInfo changedRa } @Override - public void reformatTextWithContext(PsiFile file, Collection ranges) + public void reformatTextWithContext(PsiFile file, Collection ranges) throws IncorrectOperationException { delegate.reformatTextWithContext(file, ranges); } diff --git a/idea_plugin/src/com/google/googlejavaformat/intellij/FormatterUtil.java b/idea_plugin/src/com/google/googlejavaformat/intellij/FormatterUtil.java index b6e21f78b..9939bbade 100644 --- a/idea_plugin/src/com/google/googlejavaformat/intellij/FormatterUtil.java +++ b/idea_plugin/src/com/google/googlejavaformat/intellij/FormatterUtil.java @@ -33,7 +33,7 @@ final class FormatterUtil { private FormatterUtil() {} static Map getReplacements( - Formatter formatter, String text, Collection ranges) { + Formatter formatter, String text, Collection ranges) { try { ImmutableMap.Builder replacements = ImmutableMap.builder(); formatter @@ -49,7 +49,7 @@ static Map getReplacements( } } - private static Collection> toRanges(Collection textRanges) { + private static Collection> toRanges(Collection textRanges) { return textRanges .stream() .map(textRange -> Range.closedOpen(textRange.getStartOffset(), textRange.getEndOffset())) diff --git a/idea_plugin/src/com/google/googlejavaformat/intellij/GoogleJavaFormatCodeStyleManager.java b/idea_plugin/src/com/google/googlejavaformat/intellij/GoogleJavaFormatCodeStyleManager.java index 52424c2c8..be0eac4a2 100644 --- a/idea_plugin/src/com/google/googlejavaformat/intellij/GoogleJavaFormatCodeStyleManager.java +++ b/idea_plugin/src/com/google/googlejavaformat/intellij/GoogleJavaFormatCodeStyleManager.java @@ -30,10 +30,12 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.ChangedRangesInfo; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.CheckUtil; import com.intellij.util.IncorrectOperationException; import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; @@ -60,7 +62,7 @@ public void reformatText(PsiFile file, int startOffset, int endOffset) } @Override - public void reformatText(PsiFile file, Collection ranges) + public void reformatText(PsiFile file, Collection ranges) throws IncorrectOperationException { if (overrideFormatterForFile(file)) { formatInternal(file, ranges); @@ -70,7 +72,13 @@ public void reformatText(PsiFile file, Collection ranges) } @Override - public void reformatTextWithContext(PsiFile file, Collection ranges) { + public void reformatTextWithContext(PsiFile file, ChangedRangesInfo changedRangesInfo) + throws IncorrectOperationException { + reformatTextWithContext(file, Collections.singletonList(file.getTextRange())); + } + + @Override + public void reformatTextWithContext(PsiFile file, Collection ranges) { if (overrideFormatterForFile(file)) { formatInternal(file, ranges); } else { @@ -99,7 +107,7 @@ private boolean overrideFormatterForFile(PsiFile file) { && GoogleJavaFormatSettings.getInstance(getProject()).isEnabled(); } - private void formatInternal(PsiFile file, Collection ranges) { + private void formatInternal(PsiFile file, Collection ranges) { ApplicationManager.getApplication().assertWriteAccessAllowed(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject()); documentManager.commitAllDocuments(); @@ -125,7 +133,7 @@ private void formatInternal(PsiFile file, Collection ranges) { *

Overriding methods will need to modify the document with the result of the external * formatter (usually using {@link #performReplacements(Document, Map)}. */ - private void format(Document document, Collection ranges) { + private void format(Document document, Collection ranges) { Style style = GoogleJavaFormatSettings.getInstance(getProject()).getStyle(); Formatter formatter = new Formatter(JavaFormatterOptions.builder().style(style).build()); performReplacements( diff --git a/pom.xml b/pom.xml index 87049dec4..396d7c0f9 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.google.googlejavaformat google-java-format-parent pom - 1.10-SNAPSHOT + HEAD-SNAPSHOT core @@ -118,7 +118,7 @@ com.google.errorprone error_prone_annotations - 2.0.8 + 2.5.1 @@ -180,7 +180,21 @@ ${java.version} ${java.version} + UTF-8 + true + + -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED + -J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + -XDcompilePolicy=simple -Xplugin:ErrorProne --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED @@ -195,7 +209,7 @@ com.google.errorprone error_prone_core - 2.3.2 + 2.5.1 @@ -245,7 +259,7 @@ 2.18 - -Xmx1024m + -Xmx1024m --illegal-access=permit