From a8448f28346b316e012e89e66fbdd543b57e217a Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Tue, 1 Apr 2025 15:02:06 -0700 Subject: [PATCH 01/12] Pass style into JavaInputAstVisitor This will be needed for later commits on this branch. Passed the style with which to format into JavaInputAstVisitor when it is created to allow appropriate format selection when formatting with aosp format --- .../java/com/google/googlejavaformat/java/Formatter.java | 7 ++++--- .../googlejavaformat/java/JavaInputAstVisitor.java | 9 ++++++++- .../java/java21/Java21InputAstVisitor.java | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) 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 e3b2b3235..e36d5b7ec 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/Formatter.java +++ b/core/src/main/java/com/google/googlejavaformat/java/Formatter.java @@ -28,6 +28,7 @@ import com.google.googlejavaformat.Doc; import com.google.googlejavaformat.DocBuilder; import com.google.googlejavaformat.FormattingError; +import com.google.googlejavaformat.java.JavaFormatterOptions.Style; import com.google.googlejavaformat.Newlines; import com.google.googlejavaformat.Op; import com.google.googlejavaformat.OpsBuilder; @@ -156,7 +157,7 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept createVisitor( "com.google.googlejavaformat.java.java21.Java21InputAstVisitor", builder, options); } else { - visitor = new JavaInputAstVisitor(builder, options.indentationMultiplier()); + visitor = new JavaInputAstVisitor(builder, options.indentationMultiplier(), options.style()); } visitor.scan(unit, null); builder.sync(javaInput.getText().length()); @@ -172,8 +173,8 @@ private static JavaInputAstVisitor createVisitor( try { return Class.forName(className) .asSubclass(JavaInputAstVisitor.class) - .getConstructor(OpsBuilder.class, int.class) - .newInstance(builder, options.indentationMultiplier()); + .getConstructor(OpsBuilder.class, int.class, Style.class) + .newInstance(builder, options.indentationMultiplier(), options.style()); } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } 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 f21f86a5c..416357e2a 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -80,6 +80,7 @@ import com.google.googlejavaformat.Output.BreakTag; import com.google.googlejavaformat.java.DimensionHelpers.SortedDims; import com.google.googlejavaformat.java.DimensionHelpers.TypeWithDims; +import com.google.googlejavaformat.java.JavaFormatterOptions.Style; import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ArrayAccessTree; @@ -308,6 +309,7 @@ private static ImmutableSetMultimap typeAnnotations() { protected static final Indent.Const ZERO = Indent.Const.ZERO; protected final int indentMultiplier; + protected final Style style; protected final Indent.Const minusTwo; protected final Indent.Const minusFour; protected final Indent.Const plusTwo; @@ -341,9 +343,10 @@ private static final ImmutableList forceBreakList(Optional breakTa * * @param builder the {@link OpsBuilder} */ - public JavaInputAstVisitor(OpsBuilder builder, int indentMultiplier) { + public JavaInputAstVisitor(OpsBuilder builder, int indentMultiplier, Style style) { this.builder = builder; this.indentMultiplier = indentMultiplier; + this.style = style; minusTwo = Indent.Const.make(-2, indentMultiplier); minusFour = Indent.Const.make(-4, indentMultiplier); plusTwo = Indent.Const.make(+2, indentMultiplier); @@ -357,6 +360,10 @@ private boolean inExpression() { return inExpression.peekLast(); } + private boolean useAospStyle() { + return style.equals(Style.AOSP); + } + @Override public Void scan(Tree tree, Void unused) { inExpression.addLast(tree instanceof ExpressionTree || inExpression.peekLast()); 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 029da8e04..fc0197e61 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 @@ -15,6 +15,7 @@ package com.google.googlejavaformat.java.java21; import com.google.googlejavaformat.OpsBuilder; +import com.google.googlejavaformat.java.JavaFormatterOptions.Style; import com.google.googlejavaformat.java.JavaInputAstVisitor; import com.sun.source.tree.CaseTree; import com.sun.source.tree.ConstantCaseLabelTree; @@ -33,8 +34,8 @@ */ public class Java21InputAstVisitor extends JavaInputAstVisitor { - public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier) { - super(builder, indentMultiplier); + public Java21InputAstVisitor(OpsBuilder builder, int indentMultiplier, Style style) { + super(builder, indentMultiplier, style); } @Override From e4e98dee7f9dbddb7a96b269f28a6cbf1b9990d9 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 11:21:12 -0700 Subject: [PATCH 02/12] Match Android Studio for Platform annotation formatting in aosp style --- .../google/googlejavaformat/java/JavaInputAstVisitor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 416357e2a..c0e87c261 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -4056,15 +4056,16 @@ private static Direction canLocalHaveHorizontalAnnotations(ModifiersTree modifie /** * Should a field with a set of modifiers be declared with horizontal annotations? This is - * currently true if all annotations are parameterless annotations. + * currently true if all annotations are parameterless annotations and we are not using + * AOSP style. */ - private static Direction fieldAnnotationDirection(ModifiersTree modifiers) { + private Direction fieldAnnotationDirection(ModifiersTree modifiers) { for (AnnotationTree annotation : modifiers.getAnnotations()) { if (!annotation.getArguments().isEmpty()) { return Direction.VERTICAL; } } - return Direction.HORIZONTAL; + return useAospStyle() ? Direction.VERTICAL : Direction.HORIZONTAL; } /** From b3c53a6b82f383895f384f616c043fb01a3e8747 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 12:36:06 -0700 Subject: [PATCH 03/12] Match Android Studio for Platform binary expression formatting in aosp style Android Studio for Platform has a few differences in how it formats binary expressions. This change matches them when running with --aosp. In ASfP top level binary expressions are double indented. Subexpressions are single indented. Plus operators are always single indented. --- .../java/JavaInputAstVisitor.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) 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 c0e87c261..d3b9efe70 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -305,6 +305,9 @@ private static ImmutableSetMultimap typeAnnotations() { return result.build(); } + // Used to ensure correct indentation of subexpressions in aosp style + private boolean inBinaryExpression = false; + protected final OpsBuilder builder; protected static final Indent.Const ZERO = Indent.Const.ZERO; @@ -1268,7 +1271,20 @@ public Void visitBinary(BinaryTree node, Void unused) { List operators = new ArrayList<>(); walkInfix(precedence(node), node, operands, operators); FillMode fillMode = hasOnlyShortItems(operands) ? INDEPENDENT : UNIFIED; - builder.open(plusFour); + + // Do not double indent subexpressions of a binary operator in aosp style + boolean isParentExpression = !this.inBinaryExpression; + if (useAospStyle()) { + if (isParentExpression) { + builder.open(operators.get(0).equals("+") ? plusTwo : plusFour); + } else { + builder.open(ZERO); + } + this.inBinaryExpression = true; + } else { + builder.open(plusFour); + } + scan(operands.get(0), null); int operatorsN = operators.size(); for (int i = 0; i < operatorsN; i++) { @@ -1277,6 +1293,11 @@ public Void visitBinary(BinaryTree node, Void unused) { builder.space(); scan(operands.get(i + 1), null); } + + if (isParentExpression) { + this.inBinaryExpression = false; + } + builder.close(); return null; } From 15a65dfe33c707d0f5ca301aac9ce1931a2e2c8e Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 12:49:21 -0700 Subject: [PATCH 04/12] Match Android Studio for Platform interface list formatting in aosp style Android Studio for Platform doesn't indent lists of interfaces when breaking them up over multiple lines. This matches that behavior in google-java-format when running with --aosp. --- .../google/googlejavaformat/java/JavaInputAstVisitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 d3b9efe70..fb087fa22 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -3989,7 +3989,11 @@ private void classDeclarationTypeList(String token, List types) return; } builder.breakToFill(" "); - builder.open(types.size() > 1 ? plusFour : ZERO); + if (useAospStyle()) { + builder.open(ZERO); + } else { + builder.open(types.size() > 1 ? plusFour : ZERO); + } token(token); builder.space(); boolean afterFirstToken = false; From d89d43a520692498d2680a4f0815fc477c98af9a Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 13:04:40 -0700 Subject: [PATCH 05/12] Match Android Studio for Platform dot expression formatting in aosp style Android Studio for Platform doesn't add extra indentation to dotted expressions when they are decendents of binary expressions. --- .../com/google/googlejavaformat/java/JavaInputAstVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fb087fa22..066e369e6 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -3263,7 +3263,7 @@ private void visitDotWithPrefix( // Are there method invocations or field accesses after the prefix? boolean trailingDereferences = !prefixes.isEmpty() && getLast(prefixes) < items.size() - 1; - builder.open(plusFour); + builder.open(useAospStyle() && inBinaryExpression ? ZERO : plusFour); for (int times = 0; times < prefixes.size(); times++) { builder.open(ZERO); } From 075881c1b7553330172e842bea638abc9287e466 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 14:04:32 -0700 Subject: [PATCH 06/12] Match Android Studio for Platform empty method brace formatting in aosp style Android Studio for Platform puts braces on different lines. Match that behavior in aosp style. --- .../google/googlejavaformat/java/JavaInputAstVisitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 066e369e6..7cdef03eb 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -1671,7 +1671,11 @@ public Void visitMethod(MethodTree node, Void unused) { private void methodBody(MethodTree node) { if (node.getBody().getStatements().isEmpty()) { - builder.blankLineWanted(BlankLineWanted.NO); + if (useAospStyle()) { + builder.forcedBreak(); + } else { + builder.blankLineWanted(BlankLineWanted.NO); + } } else { builder.open(plusTwo); builder.forcedBreak(); From cfa6cead72af8cd2e596c9abb5a304265eacad70 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 14:08:40 -0700 Subject: [PATCH 07/12] Match Android Studio for Platform array dimensions formatting in aosp style Android Studio for Platform does not insert an extra space between array dimensions and the initializer body. This matches that behavior. --- .../com/google/googlejavaformat/java/JavaInputAstVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7cdef03eb..97dd883ef 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -525,7 +525,7 @@ public Void visitNewArray(NewArrayTree node, Void unused) { builder.close(); } if (node.getInitializers() != null) { - if (node.getType() != null) { + if (!useAospStyle() && node.getType() != null) { builder.space(); } visitArrayInitializer(node.getInitializers()); From ee9659901e2bae15793040bc222973132aab3a52 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 15:44:08 -0700 Subject: [PATCH 08/12] Match Android Studio for Platform empty class formatting in aosp style Android Studio for Platform puts newlines in empty classes. Match that behavior in aosp style. --- .../google/googlejavaformat/java/JavaInputAstVisitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 97dd883ef..23c9d9738 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -3930,7 +3930,11 @@ protected void addBodyDeclarations( if (braces.isYes()) { builder.space(); tokenBreakTrailingComment("{", plusTwo); - builder.blankLineWanted(BlankLineWanted.NO); + if (useAospStyle()) { + builder.forcedBreak(); + } else { + builder.blankLineWanted(BlankLineWanted.NO); + } builder.open(ZERO); if (builder.peekToken().equals(Optional.of(";"))) { builder.open(plusTwo); From 64f2c20e042aef10fb4cdc9447f90e8398dbbfce Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 18:36:54 -0700 Subject: [PATCH 09/12] Match Android Studio for Platform dot expression indentation formatting in aosp style When a dot expression wraps to a new line, Android Studio for Platform doesn't wrap it. Add a stack counter for the number of dot expressions visited to be able to match this behavior in aosp style. --- .../googlejavaformat/java/JavaInputAstVisitor.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 23c9d9738..b44a77de3 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -307,6 +307,7 @@ private static ImmutableSetMultimap typeAnnotations() { // Used to ensure correct indentation of subexpressions in aosp style private boolean inBinaryExpression = false; + private int dotExpressionLevel = 0; protected final OpsBuilder builder; @@ -741,7 +742,11 @@ public Void visitNewClass(NewClassTree node, Void unused) { visitAnnotations(annotations, BreakOrNot.NO, BreakOrNot.YES); } scan(node.getIdentifier(), null); - addArguments(node.getArguments(), plusFour); + if (useAospStyle()) { + addArguments(node.getArguments(), this.dotExpressionLevel > 0 ? ZERO : plusFour); + } else { + addArguments(node.getArguments(), plusFour); + } builder.close(); if (node.getClassBody() != null) { addBodyDeclarations( @@ -3094,6 +3099,7 @@ void visitDot(ExpressionTree node0) { token("."); } else { builder.open(plusFour); + this.dotExpressionLevel++; scan(getArrayBase(node), null); builder.breakOp(); needDot = true; @@ -3101,6 +3107,7 @@ void visitDot(ExpressionTree node0) { formatArrayIndices(getArrayIndices(node)); if (stack.isEmpty()) { builder.close(); + this.dotExpressionLevel--; return; } } @@ -3171,6 +3178,7 @@ void visitDot(ExpressionTree node0) { if (node != null) { builder.close(); + this.dotExpressionLevel--; } } From a35f41758a66a7f0bda8bacf6e948609b0aefe01 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 18:42:37 -0700 Subject: [PATCH 10/12] Match Android Studio for Platform empty do-while formatting in aosp style Android Studio for Platform does not collapse empty do-while blocks. Match that behavior in aosp style. --- .../com/google/googlejavaformat/java/JavaInputAstVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b44a77de3..6412ce33d 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -792,7 +792,7 @@ public Void visitDoWhileLoop(DoWhileLoopTree node, Void unused) { token("do"); visitStatement( node.getStatement(), - CollapseEmptyOrNot.YES, + useAospStyle() ? CollapseEmptyOrNot.NO : CollapseEmptyOrNot.YES, AllowLeadingBlankLine.YES, AllowTrailingBlankLine.YES); if (node.getStatement().getKind() == BLOCK) { From dc265285a62aa0dc94c6534aa658b72c0d9205e8 Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Wed, 2 Apr 2025 18:59:31 -0700 Subject: [PATCH 11/12] Match Android Studio for Platform array initializer formatting in aosp style Android Studio for Platform uses an extra level of indentation for array initializers. Match that behavior in aosp style. --- .../java/JavaInputAstVisitor.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) 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 6412ce33d..20ce10991 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -536,6 +536,8 @@ public Void visitNewArray(NewArrayTree node, Void unused) { public boolean visitArrayInitializer(List expressions) { int cols; + final Indent.Const initializerIndent = useAospStyle() ? plusFour : plusTwo; + final Indent.Const initializerUnindent = useAospStyle() ? minusFour : minusTwo; if (expressions.isEmpty()) { tokenBreakTrailingComment("{", plusTwo); if (builder.peekToken().equals(Optional.of(","))) { @@ -543,7 +545,7 @@ public boolean visitArrayInitializer(List expressions) } token("}", plusTwo); } else if ((cols = argumentsAreTabular(expressions)) != -1) { - builder.open(plusTwo); + builder.open(initializerIndent); token("{"); builder.forcedBreak(); boolean afterFirstToken = false; @@ -565,9 +567,9 @@ public boolean visitArrayInitializer(List expressions) builder.close(); afterFirstToken = true; } - builder.breakOp(minusTwo); + builder.breakOp(initializerUnindent); builder.close(); - token("}", plusTwo); + token("}", initializerIndent); } else { // Special-case the formatting of array initializers inside annotations // to more eagerly use a one-per-line layout. @@ -587,8 +589,8 @@ public boolean visitArrayInitializer(List expressions) boolean shortItems = hasOnlyShortItems(expressions); boolean allowFilledElementsOnOwnLine = shortItems || !inMemberValuePair; - builder.open(plusTwo); - tokenBreakTrailingComment("{", plusTwo); + builder.open(initializerIndent); + tokenBreakTrailingComment("{", initializerUnindent); boolean hasTrailingComma = hasTrailingToken(builder.getInput(), expressions, ","); builder.breakOp(hasTrailingComma ? FillMode.FORCED : FillMode.UNIFIED, "", ZERO); if (allowFilledElementsOnOwnLine) { @@ -608,9 +610,9 @@ public boolean visitArrayInitializer(List expressions) if (allowFilledElementsOnOwnLine) { builder.close(); } - builder.breakOp(minusTwo); + builder.breakOp(initializerUnindent); builder.close(); - token("}", plusTwo); + token("}", initializerIndent); } return false; } From 9458d384bb032599758043f6325dba669afbfc7b Mon Sep 17 00:00:00 2001 From: Josh Gordon Date: Thu, 3 Apr 2025 11:30:44 -0700 Subject: [PATCH 12/12] Fix array indentation direction Fix a typo lower in the branch that I already pushed :) --- .../com/google/googlejavaformat/java/JavaInputAstVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 20ce10991..7f0c9dec1 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -590,7 +590,7 @@ public boolean visitArrayInitializer(List expressions) boolean allowFilledElementsOnOwnLine = shortItems || !inMemberValuePair; builder.open(initializerIndent); - tokenBreakTrailingComment("{", initializerUnindent); + tokenBreakTrailingComment("{", initializerIndent); boolean hasTrailingComma = hasTrailingToken(builder.getInput(), expressions, ","); builder.breakOp(hasTrailingComma ? FillMode.FORCED : FillMode.UNIFIED, "", ZERO); if (allowFilledElementsOnOwnLine) {