diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51ecf6e80..ab0ebf024 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# Copyright 2020 The Error Prone Authors. +# Copyright 2020 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. @@ -17,22 +17,22 @@ name: CI on: push: branches: - - master + - master pull_request: branches: - - master + - master jobs: - test: + test-OpenJDK: name: "JDK ${{ matrix.java }} on ${{ matrix.os }}" strategy: fail-fast: false matrix: - os: [ ubuntu-latest ] - java: [ 21, 17, 11 ] - experimental: [ false ] + os: [ubuntu-latest] + java: [21, 17, 11] + experimental: [false] include: - # Only test on macos and windows with a single recent JDK to avoid a + # Only test on MacOS and Windows with a single recent JDK to avoid a # combinatorial explosion of test configurations. - os: macos-latest java: 21 @@ -50,47 +50,86 @@ jobs: uses: styfle/cancel-workflow-action@0.9.1 with: access_token: ${{ github.token }} - - name: 'Check out repository' + - name: "Check out repository" uses: actions/checkout@v4 - - name: 'Set up JDK ${{ matrix.java }} from jdk.java.net' + - name: "Set up JDK ${{ matrix.java }} from jdk.java.net" if: ${{ matrix.java == 'EA' }} uses: oracle-actions/setup-java@v1 with: website: jdk.java.net release: ${{ matrix.java }} - cache: 'maven' - - name: 'Set up JDK ${{ matrix.java }}' - if: ${{ matrix.java != 'EA' }} + - name: "Set up JDK ${{ matrix.java }} from Zulu" + if: ${{ matrix.java != 'EA' && matrix.java != 'GraalVM' }} uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} - distribution: 'zulu' - cache: 'maven' - - name: 'Install' + distribution: "zulu" + cache: "maven" + - name: "Set up JDK ${{ matrix.java }}" + if: ${{ matrix.java == 'GraalVM' }} + uses: graalvm/setup-graalvm@v1 + with: + java-version: "21" + distribution: "graalvm-community" + github-token: ${{ secrets.GITHUB_TOKEN }} + native-image-job-reports: "true" + cache: "maven" + - name: "Install" shell: bash run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V - - name: 'Test' + - name: "Test" shell: bash run: mvn test -B + test-GraalVM: + name: "GraalVM on ${{ matrix.os }}" + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + continue-on-error: true + steps: + - name: Cancel previous + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + - name: "Check out repository" + uses: actions/checkout@v4 + - name: "Set up GraalVM ${{ matrix.java }}" + uses: graalvm/setup-graalvm@v1 + with: + java-version: "21" + distribution: "graalvm-community" + github-token: ${{ secrets.GITHUB_TOKEN }} + native-image-job-reports: "true" + cache: "maven" + - name: "Native Build" + run: mvn -Pnative -DskipTests package -pl core -am + - name: "Native Test" + # Bash script for testing won't work on Windows + # TODO: Anyone reading this wants to write a *.bat or *.ps1 equivalent? + if: ${{ matrix.os != 'windows-latest' }} + run: util/test-native.sh + publish_snapshot: - name: 'Publish snapshot' - needs: test + name: "Publish snapshot" + needs: test-OpenJDK if: github.event_name == 'push' && github.repository == 'google/google-java-format' && github.ref == 'refs/heads/master' runs-on: ubuntu-latest steps: - - name: 'Check out repository' + - name: "Check out repository" uses: actions/checkout@v4 - - name: 'Set up JDK 17' + - name: "Set up JDK 17" uses: actions/setup-java@v4 with: java-version: 17 - distribution: 'zulu' - cache: 'maven' + distribution: "zulu" + cache: "maven" server-id: sonatype-nexus-snapshots server-username: CI_DEPLOY_USERNAME server-password: CI_DEPLOY_PASSWORD - - name: 'Publish' + - name: "Publish" env: CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf50d61c6..2f309026b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,17 @@ +# Copyright 2020 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. + name: Release google-java-format on: @@ -20,8 +34,8 @@ jobs: uses: actions/setup-java@v4 with: java-version: 21 - distribution: 'zulu' - cache: 'maven' + distribution: "zulu" + cache: "maven" server-id: sonatype-nexus-staging server-username: CI_DEPLOY_USERNAME server-password: CI_DEPLOY_PASSWORD @@ -46,18 +60,16 @@ jobs: CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - run: - mvn --no-transfer-progress -pl '!eclipse_plugin' -P sonatype-oss-release clean deploy -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" + run: mvn --no-transfer-progress -pl '!eclipse_plugin' -P sonatype-oss-release clean deploy -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" - name: Build Eclipse plugin - run: - mvn --no-transfer-progress -pl 'eclipse_plugin' verify gpg:sign -DskipTests=true -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" + run: mvn --no-transfer-progress -pl 'eclipse_plugin' verify gpg:sign -DskipTests=true -Dgpg.passphrase="${{ secrets.GPG_PASSPHRASE }}" - name: Push tag run: | git push origin "v${{ github.event.inputs.version }}" - - name: Add Jars to Release Entry + - name: Add Artifacts to Release Entry uses: softprops/action-gh-release@v0.1.14 with: draft: true @@ -67,3 +79,34 @@ jobs: files: | core/target/google-java-format-*.jar eclipse_plugin/target/google-java-format-eclipse-plugin-*.jar + + build-native-image: + name: "Build GraalVM native-image on ${{ matrix.os }}" + runs-on: ${{ matrix.os }} + needs: build-maven-jars + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + env: + SUFFIX: ${{fromJson('{"ubuntu-latest":"linux-x86-64", "macos-latest":"darwin-arm64", "windows-latest":"windows-x86-64"}')[matrix.os]}} + EXTENSION: ${{ matrix.os == 'windows-latest' && '.exe' || '' }} + steps: + - name: "Check out repository" + uses: actions/checkout@v4 + - name: "Set up GraalVM" + uses: graalvm/setup-graalvm@v1 + with: + java-version: "21" + distribution: "graalvm-community" + github-token: ${{ secrets.GITHUB_TOKEN }} + native-image-job-reports: "true" + cache: "maven" + - name: "Native" + run: mvn -Pnative -DskipTests package -pl core -am + - name: "Move outputs" + run: cp core/target/google-java-format${{ env.EXTENSION }} google-java-format_${{ env.SUFFIX }}${{ env.EXTENSION }} + - name: "Upload native-image" + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: gh release upload "v${{ github.event.inputs.version }}" "google-java-format_${{ env.SUFFIX }}${{ env.EXTENSION }}" diff --git a/README.md b/README.md index 4fe0e2126..38fdac5e8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Using the formatter -### from the command-line +### From the command-line [Download the formatter](https://github.com/google/google-java-format/releases) and run it with: @@ -78,6 +78,8 @@ Implementation`. ### Third-party integrations +* Visual Studio Code + * [google-java-format-for-vs-code](https://marketplace.visualstudio.com/items?itemName=JoseVSeb.google-java-format-for-vs-code) * Gradle plugins * [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle#google-java-format) * [sherter/google-java-format-gradle-plugin](https://github.com/sherter/google-java-format-gradle-plugin) diff --git a/core/pom.xml b/core/pom.xml index d1363fed1..d0d803a81 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ com.google.googlejavaformat google-java-format-parent - HEAD-SNAPSHOT + 1.20.0 google-java-format @@ -282,13 +282,13 @@ org.graalvm.buildtools native-maven-plugin - 0.9.13 + 0.10.0 true build-native - build + compile-no-fork package @@ -306,9 +306,20 @@ ${project.build.directory}/${project.artifactId}-${project.version}-all-deps.jar + -H:+UnlockExperimentalVMOptions -H:IncludeResourceBundles=com.sun.tools.javac.resources.compiler + -H:IncludeResourceBundles=com.sun.tools.javac.resources.javac --no-fallback --initialize-at-build-time=com.sun.tools.javac.file.Locations + -H:+ReportExceptionStackTraces + -H:-UseContainerSupport + -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.file=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 + -march=compatibility 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 8914c8ea2..1123ac01c 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -368,16 +368,16 @@ public Void scan(Tree tree, Void unused) { @Override public Void visitCompilationUnit(CompilationUnitTree node, Void unused) { - boolean first = true; + boolean afterFirstToken = false; if (node.getPackageName() != null) { markForPartialFormat(); visitPackage(node.getPackageName(), node.getPackageAnnotations()); builder.forcedBreak(); - first = false; + afterFirstToken = true; } dropEmptyDeclarations(); if (!node.getImports().isEmpty()) { - if (!first) { + if (afterFirstToken) { builder.blankLineWanted(BlankLineWanted.YES); } for (ImportTree importDeclaration : node.getImports()) { @@ -386,7 +386,7 @@ public Void visitCompilationUnit(CompilationUnitTree node, Void unused) { scan(importDeclaration, null); builder.forcedBreak(); } - first = false; + afterFirstToken = true; } dropEmptyDeclarations(); for (Tree type : node.getTypeDecls()) { @@ -395,22 +395,22 @@ public Void visitCompilationUnit(CompilationUnitTree node, Void unused) { // TODO(cushon): remove this if https://bugs.openjdk.java.net/browse/JDK-8027682 is fixed continue; } - if (!first) { + if (afterFirstToken) { builder.blankLineWanted(BlankLineWanted.YES); } markForPartialFormat(); scan(type, null); builder.forcedBreak(); - first = false; + afterFirstToken = true; dropEmptyDeclarations(); } - handleModule(first, node); + handleModule(afterFirstToken, node); // set a partial format marker at EOF to make sure we can format the entire file markForPartialFormat(); return null; } - protected void handleModule(boolean first, CompilationUnitTree node) {} + protected void handleModule(boolean afterFirstToken, CompilationUnitTree node) {} /** Skips over extra semi-colons at the top-level, or in a class member declaration lists. */ protected void dropEmptyDeclarations() { @@ -514,9 +514,9 @@ public boolean visitArrayInitializer(List expressions) builder.open(plusTwo); token("{"); builder.forcedBreak(); - boolean first = true; + boolean afterFirstToken = false; for (Iterable row : Iterables.partition(expressions, cols)) { - if (!first) { + if (afterFirstToken) { builder.forcedBreak(); } builder.open(row.iterator().next().getKind() == NEW_ARRAY || cols == 1 ? ZERO : plusFour); @@ -531,7 +531,7 @@ public boolean visitArrayInitializer(List expressions) } builder.guessToken(","); builder.close(); - first = false; + afterFirstToken = true; } builder.breakOp(minusTwo); builder.close(); @@ -562,15 +562,15 @@ public boolean visitArrayInitializer(List expressions) if (allowFilledElementsOnOwnLine) { builder.open(ZERO); } - boolean first = true; + boolean afterFirstToken = false; FillMode fillMode = shortItems ? FillMode.INDEPENDENT : FillMode.UNIFIED; for (ExpressionTree expression : expressions) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(fillMode, " ", ZERO); } scan(expression, null); - first = false; + afterFirstToken = true; } builder.guessToken(","); if (allowFilledElementsOnOwnLine) { @@ -842,14 +842,14 @@ public boolean visitEnumDeclaration(ClassTree node) { token("implements"); builder.breakOp(" "); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; for (Tree superInterfaceType : node.getImplementsClause()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakToFill(" "); } scan(superInterfaceType, null); - first = false; + afterFirstToken = true; } builder.close(); builder.close(); @@ -893,16 +893,16 @@ public boolean visitEnumDeclaration(ClassTree node) { builder.blankLineWanted(BlankLineWanted.NO); builder.forcedBreak(); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; for (VariableTree enumConstant : enumConstants) { - if (!first) { + if (afterFirstToken) { token(","); builder.forcedBreak(); builder.blankLineWanted(BlankLineWanted.PRESERVE); } markForPartialFormat(); visitEnumConstantDeclaration(enumConstant); - first = false; + afterFirstToken = true; } if (builder.peekToken().orElse("").equals(",")) { token(","); @@ -984,18 +984,19 @@ void visitVariables( Optional.ofNullable(fragment.getInitializer()), Optional.of(";"), /* receiverExpression= */ Optional.empty(), - Optional.ofNullable(variableFragmentDims(true, 0, fragment.getType()))); + Optional.ofNullable(variableFragmentDims(false, 0, fragment.getType()))); } else { declareMany(fragments, annotationDirection); } } - private static TypeWithDims variableFragmentDims(boolean first, int leadingDims, Tree type) { + private static TypeWithDims variableFragmentDims( + boolean afterFirstToken, int leadingDims, Tree type) { if (type == null) { return null; } - if (first) { + if (!afterFirstToken) { return DimensionHelpers.extractDims(type, SortedDims.YES); } TypeWithDims dims = DimensionHelpers.extractDims(type, SortedDims.NO); @@ -1022,15 +1023,15 @@ public Void visitForLoop(ForLoopTree node, Void unused) { visitVariables( variableFragments(it, it.next()), DeclarationKind.NONE, Direction.HORIZONTAL); } else { - boolean first = true; + boolean afterFirstToken = false; builder.open(ZERO); for (StatementTree t : node.getInitializer()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(((ExpressionStatementTree) t).getExpression(), null); - first = false; + afterFirstToken = true; } token(";"); builder.close(); @@ -1087,11 +1088,11 @@ public Void visitIf(IfTree node, Void unused) { } } builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; boolean followingBlock = false; int expressionsN = expressions.size(); for (int i = 0; i < expressionsN; i++) { - if (!first) { + if (afterFirstToken) { if (followingBlock) { builder.space(); } else { @@ -1115,7 +1116,7 @@ public Void visitIf(IfTree node, Void unused) { AllowLeadingBlankLine.YES, AllowTrailingBlankLine.valueOf(trailingClauses)); followingBlock = statements.get(i).getKind() == BLOCK; - first = false; + afterFirstToken = true; } if (node.getElseStatement() != null) { if (followingBlock) { @@ -1208,15 +1209,15 @@ public Void visitInstanceOf(InstanceOfTree node, Void unused) { public Void visitIntersectionType(IntersectionTypeTree node, Void unused) { sync(node); builder.open(plusFour); - boolean first = true; + boolean afterFirstToken = false; for (Tree type : node.getBounds()) { - if (!first) { + if (afterFirstToken) { builder.breakToFill(" "); token("&"); builder.space(); } scan(type, null); - first = false; + afterFirstToken = true; } builder.close(); return null; @@ -1243,9 +1244,9 @@ public Void visitLambdaExpression(LambdaExpressionTree node, Void unused) { if (parens) { token("("); } - boolean first = true; + boolean afterFirstToken = false; for (VariableTree parameter : node.getParameters()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } @@ -1253,7 +1254,7 @@ public Void visitLambdaExpression(LambdaExpressionTree node, Void unused) { ImmutableList.of(parameter), DeclarationKind.NONE, fieldAnnotationDirection(parameter.getModifiers())); - first = false; + afterFirstToken = true; } if (parens) { token(")"); @@ -1295,14 +1296,14 @@ public Void visitAnnotation(AnnotationTree node, Void unused) { builder.open(plusFour); token("("); builder.breakOp(); - boolean first = true; + boolean afterFirstToken = false; // Format the member value pairs one-per-line if any of them are // initialized with arrays. boolean hasArrayInitializer = Iterables.any(node.getArguments(), JavaInputAstVisitor::isArrayValue); for (ExpressionTree argument : node.getArguments()) { - if (!first) { + if (afterFirstToken) { token(","); if (hasArrayInitializer) { builder.forcedBreak(); @@ -1315,7 +1316,7 @@ public Void visitAnnotation(AnnotationTree node, Void unused) { } else { scan(argument, null); } - first = false; + afterFirstToken = true; } token(")"); builder.close(); @@ -1407,6 +1408,14 @@ public Void visitMethod(MethodTree node, Void unused) { annotations, Direction.VERTICAL, /* declarationAnnotationBreak= */ Optional.empty()); + if (node.getTypeParameters().isEmpty() && node.getReturnType() != null) { + // If there are type parameters, we use a heuristic above to format annotations after the + // type parameter declarations as type-use annotations. If there are no type parameters, + // use the heuristics in visitModifiers for recognizing well known type-use annotations and + // formatting them as annotations on the return type. + returnTypeAnnotations = typeAnnotations; + typeAnnotations = ImmutableList.of(); + } Tree baseReturnType = null; Deque> dims = null; @@ -1425,44 +1434,46 @@ public Void visitMethod(MethodTree node, Void unused) { BreakTag breakBeforeType = genSym(); builder.open(ZERO); { - boolean first = true; + boolean afterFirstToken = false; if (!typeAnnotations.isEmpty()) { visitAnnotations(typeAnnotations, BreakOrNot.NO, BreakOrNot.NO); - first = false; + afterFirstToken = true; } if (!node.getTypeParameters().isEmpty()) { - if (!first) { + if (afterFirstToken) { builder.breakToFill(" "); } token("<"); typeParametersRest(node.getTypeParameters(), plusFour); - if (!returnTypeAnnotations.isEmpty()) { - builder.breakToFill(" "); - visitAnnotations(returnTypeAnnotations, BreakOrNot.NO, BreakOrNot.NO); - } - first = false; + afterFirstToken = true; } boolean openedNameAndTypeScope = false; // constructor-like declarations that don't match the name of the enclosing class are // parsed as method declarations with a null return type if (baseReturnType != null) { - if (!first) { + if (afterFirstToken) { builder.breakOp(INDEPENDENT, " ", ZERO, Optional.of(breakBeforeType)); } else { - first = false; + afterFirstToken = true; } if (!openedNameAndTypeScope) { builder.open(make(breakBeforeType, plusFour, ZERO)); openedNameAndTypeScope = true; } + builder.open(ZERO); + if (!returnTypeAnnotations.isEmpty()) { + visitAnnotations(returnTypeAnnotations, BreakOrNot.NO, BreakOrNot.NO); + builder.breakOp(" "); + } scan(baseReturnType, null); maybeAddDims(dims); + builder.close(); } - if (!first) { + if (afterFirstToken) { builder.breakOp(Doc.FillMode.INDEPENDENT, " ", ZERO, Optional.of(breakBeforeName)); } else { - first = false; + afterFirstToken = true; } if (!openedNameAndTypeScope) { builder.open(ZERO); @@ -1702,14 +1713,14 @@ public Void visitParameterizedType(ParameterizedTypeTree node, Void unused) { token("<"); builder.breakOp(); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; for (Tree typeArgument : node.getTypeArguments()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(typeArgument, null); - first = false; + afterFirstToken = true; } builder.close(); builder.close(); @@ -1895,13 +1906,13 @@ protected void visitSwitch(ExpressionTree expression, List c tokenBreakTrailingComment("{", plusTwo); builder.blankLineWanted(BlankLineWanted.NO); builder.open(plusTwo); - boolean first = true; + boolean afterFirstToken = false; for (CaseTree caseTree : cases) { - if (!first) { + if (afterFirstToken) { builder.blankLineWanted(BlankLineWanted.PRESERVE); } scan(caseTree, null); - first = false; + afterFirstToken = true; } builder.close(); builder.forcedBreak(); @@ -1944,9 +1955,9 @@ public Void visitTry(TryTree node, Void unused) { if (!node.getResources().isEmpty()) { token("("); builder.open(node.getResources().size() > 1 ? plusFour : ZERO); - boolean first = true; + boolean afterFirstToken = false; for (Tree resource : node.getResources()) { - if (!first) { + if (afterFirstToken) { builder.forcedBreak(); } if (resource instanceof VariableTree) { @@ -1971,7 +1982,7 @@ public Void visitTry(TryTree node, Void unused) { token(";"); builder.space(); } - first = false; + afterFirstToken = true; } if (builder.peekToken().equals(Optional.of(";"))) { token(";"); @@ -2060,15 +2071,15 @@ public Void visitTypeParameter(TypeParameterTree node, Void unused) { builder.open(plusFour); builder.breakOp(" "); builder.open(plusFour); - boolean first = true; + boolean afterFirstToken = false; for (Tree typeBound : node.getBounds()) { - if (!first) { + if (afterFirstToken) { builder.breakToFill(" "); token("&"); builder.space(); } scan(typeBound, null); - first = false; + afterFirstToken = true; } builder.close(); builder.close(); @@ -2124,13 +2135,13 @@ protected void visitAnnotations( if (breakBefore.isYes()) { builder.breakToFill(" "); } - boolean first = true; + boolean afterFirstToken = false; for (AnnotationTree annotation : annotations) { - if (!first) { + if (afterFirstToken) { builder.breakToFill(" "); } scan(annotation, null); - first = false; + afterFirstToken = true; } if (breakAfter.isYes()) { builder.breakToFill(" "); @@ -2210,17 +2221,17 @@ private void visitStatement( } protected void visitStatements(List statements) { - boolean first = true; + boolean afterFirstToken = false; PeekingIterator it = Iterators.peekingIterator(statements.iterator()); dropEmptyDeclarations(); while (it.hasNext()) { StatementTree tree = it.next(); builder.forcedBreak(); - if (!first) { + if (afterFirstToken) { builder.blankLineWanted(BlankLineWanted.PRESERVE); } markForPartialFormat(); - first = false; + afterFirstToken = true; List fragments = variableFragments(it, tree); if (!fragments.isEmpty()) { visitVariables( @@ -2290,17 +2301,17 @@ private ImmutableList visitModifiers( Deque declarationModifiers = new ArrayDeque<>(splitModifiers.declarationModifiers()); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; boolean lastWasAnnotation = false; while (!declarationModifiers.isEmpty() && !declarationModifiers.peekFirst().isModifier()) { - if (!first) { + if (afterFirstToken) { builder.addAll( annotationsDirection.isVertical() ? forceBreakList(declarationAnnotationBreak) : breakList(declarationAnnotationBreak)); } formatAnnotationOrModifier(declarationModifiers); - first = false; + afterFirstToken = true; lastWasAnnotation = true; } builder.close(); @@ -2317,13 +2328,13 @@ private ImmutableList visitModifiers( } builder.open(ZERO); - first = true; + afterFirstToken = false; while (!declarationModifiers.isEmpty()) { - if (!first) { + if (afterFirstToken) { builder.addAll(breakFillList(Optional.empty())); } formatAnnotationOrModifier(declarationModifiers); - first = false; + afterFirstToken = true; } builder.close(); builder.addAll(breakFillList(Optional.empty())); @@ -2546,14 +2557,14 @@ private void visitUnionType(VariableTree declaration) { Direction.HORIZONTAL, /* declarationAnnotationBreak= */ Optional.empty()); List union = type.getTypeAlternatives(); - boolean first = true; + boolean afterFirstToken = false; for (int i = 0; i < union.size() - 1; i++) { - if (!first) { + if (afterFirstToken) { builder.breakOp(" "); token("|"); builder.space(); } else { - first = false; + afterFirstToken = true; } scan(union.get(i), null); } @@ -2602,7 +2613,7 @@ protected void visitFormals( return; } builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; if (receiver.isPresent()) { // TODO(user): Use builders. declareOne( @@ -2617,11 +2628,11 @@ protected void visitFormals( !parameters.isEmpty() ? Optional.of(",") : Optional.empty(), Optional.of(receiver.get().getNameExpression()), /* typeWithDims= */ Optional.empty()); - first = false; + afterFirstToken = true; } for (int i = 0; i < parameters.size(); i++) { VariableTree parameter = parameters.get(i); - if (!first) { + if (afterFirstToken) { builder.breakOp(" "); } visitToDeclare( @@ -2631,7 +2642,7 @@ protected void visitFormals( /* initializer= */ Optional.empty(), "=", i < parameters.size() - 1 ? Optional.of(",") : /* a= */ Optional.empty()); - first = false; + afterFirstToken = true; } builder.close(); } @@ -2640,14 +2651,14 @@ protected void visitFormals( private void visitThrowsClause(List thrownExceptionTypes) { token("throws"); builder.breakToFill(" "); - boolean first = true; + boolean afterFirstToken = false; for (ExpressionTree thrownExceptionType : thrownExceptionTypes) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(thrownExceptionType, null); - first = false; + afterFirstToken = true; } } @@ -2711,14 +2722,14 @@ private void visitDirective( builder.space(); token(separator); builder.forcedBreak(); - boolean first = true; + boolean afterFirstToken = false; for (ExpressionTree item : items) { - if (!first) { + if (afterFirstToken) { token(","); builder.forcedBreak(); } scan(item, null); - first = false; + afterFirstToken = true; } token(";"); builder.close(); @@ -2781,13 +2792,13 @@ private void visitName(Tree node) { stack.addFirst(((MemberSelectTree) node).getIdentifier()); } stack.addFirst(((IdentifierTree) node).getName()); - boolean first = true; + boolean afterFirstToken = false; for (Name name : stack) { - if (!first) { + if (afterFirstToken) { token("."); } token(name.toString()); - first = false; + afterFirstToken = true; } } @@ -2829,14 +2840,14 @@ protected void typeParametersRest( builder.open(plusIndent); builder.breakOp(); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; for (TypeParameterTree typeParameter : typeParameters) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(typeParameter, null); - first = false; + afterFirstToken = true; } token(">"); builder.close(); @@ -3228,14 +3239,14 @@ void addTypeArguments(List typeArguments, Indent plusIndent) { } token("<"); builder.open(plusIndent); - boolean first = true; + boolean afterFirstToken = false; for (Tree typeArgument : typeArguments) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakToFill(" "); } scan(typeArgument, null); - first = false; + afterFirstToken = true; } builder.close(); token(">"); @@ -3256,11 +3267,11 @@ void addArguments(List arguments, Indent plusIndent) { if (arguments.size() % 2 == 0 && argumentsAreTabular(arguments) == 2) { builder.forcedBreak(); builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; for (int i = 0; i < arguments.size() - 1; i += 2) { ExpressionTree argument0 = arguments.get(i); ExpressionTree argument1 = arguments.get(i + 1); - if (!first) { + if (afterFirstToken) { token(","); builder.forcedBreak(); } @@ -3270,7 +3281,7 @@ void addArguments(List arguments, Indent plusIndent) { builder.breakOp(" "); scan(argument1, null); builder.close(); - first = false; + afterFirstToken = true; } builder.close(); } else if (isFormatMethod(arguments)) { @@ -3294,15 +3305,15 @@ void addArguments(List arguments, Indent plusIndent) { private void argList(List arguments) { builder.open(ZERO); - boolean first = true; + boolean afterFirstToken = false; FillMode fillMode = hasOnlyShortItems(arguments) ? FillMode.INDEPENDENT : FillMode.UNIFIED; for (ExpressionTree argument : arguments) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(fillMode, " ", ZERO); } scan(argument, null); - first = false; + afterFirstToken = true; } builder.close(); } @@ -3691,12 +3702,13 @@ private void declareMany(List fragments, Direction annotationDirec int baseDims = dims.size(); maybeAddDims(dims); baseDims = baseDims - dims.size(); - boolean first = true; + boolean afterFirstToken = false; for (VariableTree fragment : fragments) { - if (!first) { + if (afterFirstToken) { token(","); } - TypeWithDims fragmentDims = variableFragmentDims(first, baseDims, fragment.getType()); + TypeWithDims fragmentDims = + variableFragmentDims(afterFirstToken, baseDims, fragment.getType()); dims = new ArrayDeque<>(fragmentDims.dims); builder.breakOp(" "); builder.open(ZERO); @@ -3713,10 +3725,10 @@ private void declareMany(List fragments, Direction annotationDirec builder.close(); } builder.close(); - if (first) { + if (!afterFirstToken) { builder.close(); } - first = false; + afterFirstToken = true; } builder.close(); token(";"); @@ -3795,14 +3807,14 @@ private void classDeclarationTypeList(String token, List types) builder.open(types.size() > 1 ? plusFour : ZERO); token(token); builder.space(); - boolean first = true; + boolean afterFirstToken = false; for (Tree type : types) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(type, null); - first = false; + afterFirstToken = true; } builder.close(); } diff --git a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java index a7b5dbc44..e502f49a1 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/java17/Java17InputAstVisitor.java @@ -55,10 +55,10 @@ public Java17InputAstVisitor(OpsBuilder builder, int indentMultiplier) { } @Override - protected void handleModule(boolean first, CompilationUnitTree node) { + protected void handleModule(boolean afterFirstToken, CompilationUnitTree node) { ModuleTree module = node.getModule(); if (module != null) { - if (!first) { + if (afterFirstToken) { builder.blankLineWanted(BlankLineWanted.YES); } markForPartialFormat(); @@ -167,14 +167,14 @@ public void visitRecordDeclaration(ClassTree node) { builder.open(node.getImplementsClause().size() > 1 ? plusFour : ZERO); token("implements"); builder.space(); - boolean first = true; + boolean afterFirstToken = false; for (Tree superInterfaceType : node.getImplementsClause()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(superInterfaceType, null); - first = false; + afterFirstToken = true; } builder.close(); } @@ -238,14 +238,14 @@ public Void visitCase(CaseTree node, Void unused) { token("case", plusTwo); builder.open(labels.size() > 1 ? plusFour : ZERO); builder.space(); - boolean first = true; + boolean afterFirstToken = false; for (Tree expression : labels) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } scan(expression, null); - first = false; + afterFirstToken = true; } builder.close(); } 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 index 5ef81fad6..2192a32a9 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/java21/Java21InputAstVisitor.java @@ -24,6 +24,8 @@ import com.sun.source.tree.PatternCaseLabelTree; import com.sun.source.tree.PatternTree; import com.sun.source.tree.StringTemplateTree; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.tree.JCTree; import javax.lang.model.element.Name; /** @@ -66,13 +68,13 @@ public Void visitDeconstructionPattern(DeconstructionPatternTree node, Void unus builder.open(plusFour); token("("); builder.breakOp(); - boolean first = true; + boolean afterFirstToken = false; for (PatternTree pattern : node.getNestedPatterns()) { - if (!first) { + if (afterFirstToken) { token(","); builder.breakOp(" "); } - first = false; + afterFirstToken = true; scan(pattern, null); } builder.close(); @@ -107,4 +109,20 @@ protected void variableName(Name name) { visit(name); } } + + @Override + public Void scan(Tree tree, Void unused) { + // Pre-visit AST for preview features, since com.sun.source.tree.AnyPattern can't be + // accessed directly without --enable-preview. + if (tree instanceof JCTree.JCAnyPattern) { + visitJcAnyPattern((JCTree.JCAnyPattern) tree); + return null; + } else { + return super.scan(tree, unused); + } + } + + private void visitJcAnyPattern(JCTree.JCAnyPattern unused) { + token("_"); + } } diff --git a/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java b/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java index 1a4ed09b4..08fbbbab3 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java @@ -15,7 +15,6 @@ 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 static org.junit.Assert.fail; 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 5fb356750..15a6e75f9 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java @@ -62,7 +62,8 @@ public class FormatterIntegrationTest { "Unnamed", "I981", "StringTemplate", - "I1020") + "I1020", + "I1037") .build(); @Parameters(name = "{index}: {0}") @@ -104,10 +105,9 @@ public static Iterable data() throws IOException { String expectedOutput = outputs.get(fileName); Optional version = VERSIONED_TESTS.inverse().get(fileName).stream().collect(toOptional()); - if (Runtime.version().feature() < version.orElse(Integer.MAX_VALUE)) { - continue; + if (Runtime.version().feature() >= version.orElse(Integer.MIN_VALUE)) { + testInputs.add(new Object[] {fileName, input, expectedOutput}); } - testInputs.add(new Object[] {fileName, input, expectedOutput}); } return testInputs; } 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 3d41a0733..461bd6793 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolProviderTest.java @@ -15,7 +15,6 @@ package com.google.googlejavaformat.java; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java index 691bb2234..e3a7573a7 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/GoogleJavaFormatToolTest.java @@ -15,7 +15,6 @@ 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; diff --git a/core/src/test/java/com/google/googlejavaformat/java/TypeNameClassifierTest.java b/core/src/test/java/com/google/googlejavaformat/java/TypeNameClassifierTest.java index 3270bc64e..6d7e5666c 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/TypeNameClassifierTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/TypeNameClassifierTest.java @@ -15,7 +15,6 @@ package com.google.googlejavaformat.java; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.google.common.base.Splitter; import com.google.googlejavaformat.java.TypeNameClassifier.JavaCaseFormat; diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.input new file mode 100644 index 000000000..931a7d726 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.input @@ -0,0 +1,11 @@ +class WrapTypeUse { + public static final @Nullable + WrapTypeUse get() { + return null; + } + + public @Nullable + Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx getXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx() { + return null; + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.output new file mode 100644 index 000000000..b34bdb38c --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B322210626.output @@ -0,0 +1,11 @@ +class WrapTypeUse { + public static final + @Nullable WrapTypeUse get() { + return null; + } + + public @Nullable Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + getXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx() { + return null; + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.input new file mode 100644 index 000000000..ed39459dd --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.input @@ -0,0 +1,11 @@ +public sealed interface A { + record AA(Long a) implements A {} + + static Long mySwitch(A a) { + switch (a) { + case AA(_) -> { + return 1L; + } + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.output new file mode 100644 index 000000000..ed39459dd --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I1037.output @@ -0,0 +1,11 @@ +public sealed interface A { + record AA(Long a) implements A {} + + static Long mySwitch(A a) { + switch (a) { + case AA(_) -> { + return 1L; + } + } + } +} diff --git a/eclipse_plugin/META-INF/MANIFEST.MF b/eclipse_plugin/META-INF/MANIFEST.MF index 913245393..531fb8410 100644 --- a/eclipse_plugin/META-INF/MANIFEST.MF +++ b/eclipse_plugin/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: google-java-format Bundle-SymbolicName: google-java-format-eclipse-plugin;singleton:=true Bundle-Vendor: Google -Bundle-Version: 1.13.0 +Bundle-Version: 1.20.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Require-Bundle: org.eclipse.jdt.core;bundle-version="3.10.0", org.eclipse.jface, diff --git a/eclipse_plugin/pom.xml b/eclipse_plugin/pom.xml index 9e6acdac0..25b2bac8a 100644 --- a/eclipse_plugin/pom.xml +++ b/eclipse_plugin/pom.xml @@ -22,7 +22,7 @@ com.google.googlejavaformat google-java-format-eclipse-plugin eclipse-plugin - 1.13.0 + 1.20.0 Google Java Format Plugin for Eclipse 4.5+ diff --git a/idea_plugin/build.gradle.kts b/idea_plugin/build.gradle.kts index 5e965823f..2247893c1 100644 --- a/idea_plugin/build.gradle.kts +++ b/idea_plugin/build.gradle.kts @@ -14,7 +14,7 @@ * limitations under the License. */ -plugins { id("org.jetbrains.intellij") version "1.15.0" } +plugins { id("org.jetbrains.intellij") version "1.16.1" } apply(plugin = "org.jetbrains.intellij") @@ -22,7 +22,7 @@ apply(plugin = "java") repositories { mavenCentral() } -val googleJavaFormatVersion = "1.17.0" +val googleJavaFormatVersion = "1.19.2" java { sourceCompatibility = JavaVersion.VERSION_11 @@ -62,5 +62,5 @@ tasks { dependencies { implementation("com.google.googlejavaformat:google-java-format:${googleJavaFormatVersion}") testImplementation("junit:junit:4.13.2") - testImplementation("com.google.truth:truth:1.1.5") + testImplementation("com.google.truth:truth:1.2.0") } diff --git a/idea_plugin/src/main/resources/META-INF/plugin.xml b/idea_plugin/src/main/resources/META-INF/plugin.xml index 1b1e67ffa..a5600b00d 100644 --- a/idea_plugin/src/main/resources/META-INF/plugin.xml +++ b/idea_plugin/src/main/resources/META-INF/plugin.xml @@ -35,6 +35,8 @@ ]]> +
1.19.2.0
+
Updated to use google-java-format 1.19.2.
1.17.0.0
Updated to use google-java-format 1.17.0.
Fixed "Document is locked" errors (Thanks, @facboy!)
diff --git a/pom.xml b/pom.xml index 8b3ca51cd..04abf5c3b 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ com.google.googlejavaformat google-java-format-parent pom - HEAD-SNAPSHOT + 1.20.0 core @@ -87,12 +87,12 @@ UTF-8 1.8 32.1.3-jre - 1.1.3 + 1.4.0 3.21.2 2.16 1.9 1.0.1 - 3.4.0 + 3.6.3 3.2.1 @@ -172,7 +172,7 @@ maven-javadoc-plugin - 3.4.0 + ${maven-javadoc-plugin.version} maven-gpg-plugin @@ -260,7 +260,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.0 + ${maven-javadoc-plugin.version} none diff --git a/util/test-native.sh b/util/test-native.sh new file mode 100755 index 000000000..a8643baf2 --- /dev/null +++ b/util/test-native.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Copyright 2024 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. + +set -euox pipefail + +time java -jar core/target/google-java-format-*-all-deps.jar || true + +status=-1 +chmod +x core/target/google-java-format +if time core/target/google-java-format; then + status=0 +else + status=$? +fi +if [[ $status -ne 2 ]]; then + echo "google-java-format_linux (native) without arguments should have printed usage help and exited with 2, but did not :(" + exit 1 +fi