1414
1515package com .google .googlejavaformat .java ;
1616
17+ import static com .google .common .collect .ImmutableList .toImmutableList ;
1718import static com .google .common .collect .Iterables .getLast ;
1819import static com .google .common .collect .Iterables .getOnlyElement ;
1920import static com .google .googlejavaformat .Doc .FillMode .INDEPENDENT ;
8485import com .sun .source .tree .AssertTree ;
8586import com .sun .source .tree .AssignmentTree ;
8687import com .sun .source .tree .BinaryTree ;
88+ import com .sun .source .tree .BindingPatternTree ;
8789import com .sun .source .tree .BlockTree ;
8890import com .sun .source .tree .BreakTree ;
91+ import com .sun .source .tree .CaseLabelTree ;
8992import com .sun .source .tree .CaseTree ;
9093import com .sun .source .tree .CatchTree ;
9194import com .sun .source .tree .ClassTree ;
125128import com .sun .source .tree .RequiresTree ;
126129import com .sun .source .tree .ReturnTree ;
127130import com .sun .source .tree .StatementTree ;
131+ import com .sun .source .tree .SwitchExpressionTree ;
128132import com .sun .source .tree .SwitchTree ;
129133import com .sun .source .tree .SynchronizedTree ;
130134import com .sun .source .tree .ThrowTree ;
138142import com .sun .source .tree .VariableTree ;
139143import com .sun .source .tree .WhileLoopTree ;
140144import com .sun .source .tree .WildcardTree ;
145+ import com .sun .source .tree .YieldTree ;
141146import com .sun .source .util .TreePath ;
142147import com .sun .source .util .TreePathScanner ;
143148import com .sun .tools .javac .code .Flags ;
144149import com .sun .tools .javac .tree .JCTree ;
145150import com .sun .tools .javac .tree .JCTree .JCMethodDecl ;
151+ import com .sun .tools .javac .tree .TreeInfo ;
146152import com .sun .tools .javac .tree .TreeScanner ;
147153import java .util .ArrayDeque ;
148154import java .util .ArrayList ;
@@ -410,7 +416,17 @@ public Void visitCompilationUnit(CompilationUnitTree node, Void unused) {
410416 return null ;
411417 }
412418
413- protected void handleModule (boolean afterFirstToken , CompilationUnitTree node ) {}
419+ protected void handleModule (boolean afterFirstToken , CompilationUnitTree node ) {
420+ ModuleTree module = node .getModule ();
421+ if (module != null ) {
422+ if (afterFirstToken ) {
423+ builder .blankLineWanted (YES );
424+ }
425+ markForPartialFormat ();
426+ visitModule (module , null );
427+ builder .forcedBreak ();
428+ }
429+ }
414430
415431 /** Skips over extra semi-colons at the top-level, or in a class member declaration lists. */
416432 protected void dropEmptyDeclarations () {
@@ -436,6 +452,9 @@ public Void visitClass(ClassTree tree, Void unused) {
436452 case ENUM :
437453 visitEnumDeclaration (tree );
438454 break ;
455+ case RECORD :
456+ visitRecordDeclaration (tree );
457+ break ;
439458 default :
440459 throw new AssertionError (tree .getKind ());
441460 }
@@ -928,6 +947,69 @@ public boolean visitEnumDeclaration(ClassTree node) {
928947 return false ;
929948 }
930949
950+ public void visitRecordDeclaration (ClassTree node ) {
951+ sync (node );
952+ typeDeclarationModifiers (node .getModifiers ());
953+ Verify .verify (node .getExtendsClause () == null );
954+ boolean hasSuperInterfaceTypes = !node .getImplementsClause ().isEmpty ();
955+ token ("record" );
956+ builder .space ();
957+ visit (node .getSimpleName ());
958+ if (!node .getTypeParameters ().isEmpty ()) {
959+ token ("<" );
960+ }
961+ builder .open (plusFour );
962+ {
963+ if (!node .getTypeParameters ().isEmpty ()) {
964+ typeParametersRest (node .getTypeParameters (), hasSuperInterfaceTypes ? plusFour : ZERO );
965+ }
966+ ImmutableList <JCTree .JCVariableDecl > parameters = JavaInputAstVisitor .recordVariables (node );
967+ token ("(" );
968+ if (!parameters .isEmpty ()) {
969+ // Break before args.
970+ builder .breakToFill ("" );
971+ }
972+ // record headers can't declare receiver parameters
973+ visitFormals (/* receiver= */ Optional .empty (), parameters );
974+ token (")" );
975+ if (hasSuperInterfaceTypes ) {
976+ builder .breakToFill (" " );
977+ builder .open (node .getImplementsClause ().size () > 1 ? plusFour : ZERO );
978+ token ("implements" );
979+ builder .space ();
980+ boolean afterFirstToken = false ;
981+ for (Tree superInterfaceType : node .getImplementsClause ()) {
982+ if (afterFirstToken ) {
983+ token ("," );
984+ builder .breakOp (" " );
985+ }
986+ scan (superInterfaceType , null );
987+ afterFirstToken = true ;
988+ }
989+ builder .close ();
990+ }
991+ }
992+ builder .close ();
993+ if (node .getMembers () == null ) {
994+ token (";" );
995+ } else {
996+ ImmutableList <Tree > members =
997+ node .getMembers ().stream ()
998+ .filter (t -> (TreeInfo .flags ((JCTree ) t ) & Flags .GENERATED_MEMBER ) == 0 )
999+ .collect (toImmutableList ());
1000+ addBodyDeclarations (members , BracesOrNot .YES , FirstDeclarationsOrNot .YES );
1001+ }
1002+ dropEmptyDeclarations ();
1003+ }
1004+
1005+ private static ImmutableList <JCTree .JCVariableDecl > recordVariables (ClassTree node ) {
1006+ return node .getMembers ().stream ()
1007+ .filter (JCTree .JCVariableDecl .class ::isInstance )
1008+ .map (JCTree .JCVariableDecl .class ::cast )
1009+ .filter (m -> (m .mods .flags & RECORD ) == RECORD )
1010+ .collect (toImmutableList ());
1011+ }
1012+
9311013 @ Override
9321014 public Void visitMemberReference (MemberReferenceTree node , Void unused ) {
9331015 builder .open (plusFour );
@@ -1199,7 +1281,11 @@ public Void visitInstanceOf(InstanceOfTree node, Void unused) {
11991281 builder .open (ZERO );
12001282 token ("instanceof" );
12011283 builder .breakOp (" " );
1202- scan (node .getType (), null );
1284+ if (node .getPattern () != null ) {
1285+ scan (node .getPattern (), null );
1286+ } else {
1287+ scan (node .getType (), null );
1288+ }
12031289 builder .close ();
12041290 builder .close ();
12051291 return null ;
@@ -1874,18 +1960,69 @@ public Void visitCase(CaseTree node, Void unused) {
18741960 sync (node );
18751961 markForPartialFormat ();
18761962 builder .forcedBreak ();
1877- if (node .getExpression () == null ) {
1963+ List <? extends CaseLabelTree > labels = node .getLabels ();
1964+ boolean isDefault =
1965+ labels .size () == 1 && getOnlyElement (labels ).getKind ().name ().equals ("DEFAULT_CASE_LABEL" );
1966+ builder .open (node .getCaseKind ().equals (CaseTree .CaseKind .RULE ) ? plusFour : ZERO );
1967+ if (isDefault ) {
18781968 token ("default" , ZERO );
1879- token (":" );
18801969 } else {
18811970 token ("case" , ZERO );
1971+ builder .open (ZERO );
18821972 builder .space ();
1883- scan (node .getExpression (), null );
1884- token (":" );
1973+ boolean afterFirstToken = false ;
1974+ for (Tree expression : labels ) {
1975+ if (afterFirstToken ) {
1976+ token ("," );
1977+ builder .breakOp (" " );
1978+ }
1979+ scan (expression , null );
1980+ afterFirstToken = true ;
1981+ }
1982+ builder .close ();
1983+ }
1984+
1985+ final ExpressionTree guard = getGuard (node );
1986+ if (guard != null ) {
1987+ builder .breakToFill (" " );
1988+ token ("when" );
1989+ builder .space ();
1990+ scan (guard , null );
1991+ }
1992+
1993+ switch (node .getCaseKind ()) {
1994+ case STATEMENT :
1995+ token (":" );
1996+ builder .open (plusTwo );
1997+ visitStatements (node .getStatements ());
1998+ builder .close ();
1999+ builder .close ();
2000+ break ;
2001+ case RULE :
2002+ builder .space ();
2003+ token ("-" );
2004+ token (">" );
2005+ if (node .getBody ().getKind () == BLOCK ) {
2006+ builder .close ();
2007+ builder .space ();
2008+ // Explicit call with {@link CollapseEmptyOrNot.YES} to handle empty case blocks.
2009+ visitBlock (
2010+ (BlockTree ) node .getBody (),
2011+ CollapseEmptyOrNot .YES ,
2012+ AllowLeadingBlankLine .NO ,
2013+ AllowTrailingBlankLine .NO );
2014+ } else {
2015+ builder .breakOp (" " );
2016+ scan (node .getBody (), null );
2017+ builder .close ();
2018+ }
2019+ builder .guessToken (";" );
2020+ break ;
18852021 }
1886- builder .open (plusTwo );
1887- visitStatements (node .getStatements ());
1888- builder .close ();
2022+ return null ;
2023+ }
2024+
2025+ protected ExpressionTree getGuard (final CaseTree node ) {
18892026 return null ;
18902027 }
18912028
@@ -2022,7 +2159,7 @@ public Void visitTry(TryTree node, Void unused) {
20222159 public void visitClassDeclaration (ClassTree node ) {
20232160 sync (node );
20242161 typeDeclarationModifiers (node .getModifiers ());
2025- List <? extends Tree > permitsTypes = getPermitsClause (node );
2162+ List <? extends Tree > permitsTypes = node . getPermitsClause ();
20262163 boolean hasSuperclassType = node .getExtendsClause () != null ;
20272164 boolean hasSuperInterfaceTypes = !node .getImplementsClause ().isEmpty ();
20282165 boolean hasPermitsTypes = !permitsTypes .isEmpty ();
@@ -3800,11 +3937,6 @@ protected void addBodyDeclarations(
38003937 }
38013938 }
38023939
3803- /** Gets the permits clause for the given node. This is only available in Java 15 and later. */
3804- protected List <? extends Tree > getPermitsClause (ClassTree node ) {
3805- return ImmutableList .of ();
3806- }
3807-
38083940 private void classDeclarationTypeList (String token , List <? extends Tree > types ) {
38093941 if (types .isEmpty ()) {
38103942 return ;
@@ -3966,4 +4098,40 @@ final BreakTag genSym() {
39664098 public final String toString () {
39674099 return MoreObjects .toStringHelper (this ).add ("builder" , builder ).toString ();
39684100 }
4101+
4102+ @ Override
4103+ public Void visitBindingPattern (BindingPatternTree node , Void unused ) {
4104+ sync (node );
4105+ VariableTree variableTree = node .getVariable ();
4106+ declareOne (
4107+ DeclarationKind .PARAMETER ,
4108+ Direction .HORIZONTAL ,
4109+ Optional .of (variableTree .getModifiers ()),
4110+ variableTree .getType (),
4111+ variableTree .getName (),
4112+ /* op= */ "" ,
4113+ /* equals= */ "" ,
4114+ /* initializer= */ Optional .empty (),
4115+ /* trailing= */ Optional .empty (),
4116+ /* receiverExpression= */ Optional .empty (),
4117+ /* typeWithDims= */ Optional .empty ());
4118+ return null ;
4119+ }
4120+
4121+ @ Override
4122+ public Void visitYield (YieldTree node , Void aVoid ) {
4123+ sync (node );
4124+ token ("yield" );
4125+ builder .space ();
4126+ scan (node .getValue (), null );
4127+ token (";" );
4128+ return null ;
4129+ }
4130+
4131+ @ Override
4132+ public Void visitSwitchExpression (SwitchExpressionTree node , Void aVoid ) {
4133+ sync (node );
4134+ visitSwitch (node .getExpression (), node .getCases ());
4135+ return null ;
4136+ }
39694137}
0 commit comments