• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3  * Copyright (C) 2011, 2013-2016 The JavaParser Team.
4  *
5  * This file is part of JavaParser.
6  *
7  * JavaParser can be used either under the terms of
8  * a) the GNU Lesser General Public License as published by
9  *     the Free Software Foundation, either version 3 of the License, or
10  *     (at your option) any later version.
11  * b) the terms of the Apache License
12  *
13  * You should have received a copy of both licenses in LICENCE.LGPL and
14  * LICENCE.APACHE. Please refer to those files for details.
15  *
16  * JavaParser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  */
21 
22 package com.github.javaparser.printer;
23 
24 import com.github.javaparser.ast.*;
25 import com.github.javaparser.ast.body.*;
26 import com.github.javaparser.ast.comments.BlockComment;
27 import com.github.javaparser.ast.comments.Comment;
28 import com.github.javaparser.ast.comments.JavadocComment;
29 import com.github.javaparser.ast.comments.LineComment;
30 import com.github.javaparser.ast.expr.*;
31 import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments;
32 import com.github.javaparser.ast.nodeTypes.NodeWithVariables;
33 import com.github.javaparser.ast.stmt.*;
34 import com.github.javaparser.ast.type.*;
35 import com.github.javaparser.ast.visitor.VoidVisitor;
36 
37 import java.util.EnumSet;
38 import java.util.Iterator;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.stream.Collectors;
42 
43 import static com.github.javaparser.utils.PositionUtils.sortByBeginPosition;
44 import static com.github.javaparser.utils.Utils.isNullOrEmpty;
45 
46 /**
47  * Outputs the AST as formatted Java source code.
48  *
49  * @author Julio Vilmar Gesser
50  */
51 public class PrettyPrintVisitor implements VoidVisitor<Void> {
52     protected final PrettyPrinterConfiguration configuration;
53     protected final SourcePrinter printer;
54 
PrettyPrintVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration)55     public PrettyPrintVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration) {
56         configuration = prettyPrinterConfiguration;
57         printer = new SourcePrinter(configuration.getIndent());
58     }
59 
getSource()60     public String getSource() {
61         return printer.getSource();
62     }
63 
printModifiers(final EnumSet<Modifier> modifiers)64     private void printModifiers(final EnumSet<Modifier> modifiers) {
65         if (modifiers.size() > 0) {
66             printer.print(modifiers.stream().map(Modifier::asString).collect(Collectors.joining(" ")) + " ");
67         }
68     }
69 
printMembers(final NodeList<BodyDeclaration<?>> members, final Void arg)70     private void printMembers(final NodeList<BodyDeclaration<?>> members, final Void arg) {
71         for (final BodyDeclaration<?> member : members) {
72             printer.println();
73             member.accept(this, arg);
74             printer.println();
75         }
76     }
77 
printMemberAnnotations(final NodeList<AnnotationExpr> annotations, final Void arg)78     private void printMemberAnnotations(final NodeList<AnnotationExpr> annotations, final Void arg) {
79         if (annotations.isEmpty()) {
80             return;
81         }
82         for (final AnnotationExpr a : annotations) {
83             a.accept(this, arg);
84             printer.println();
85         }
86     }
87 
printAnnotations(final NodeList<AnnotationExpr> annotations, boolean prefixWithASpace, final Void arg)88     private void printAnnotations(final NodeList<AnnotationExpr> annotations, boolean prefixWithASpace,
89                                   final Void arg) {
90         if (annotations.isEmpty()) {
91             return;
92         }
93         if (prefixWithASpace) {
94             printer.print(" ");
95         }
96         for (AnnotationExpr annotation : annotations) {
97             annotation.accept(this, arg);
98             printer.print(" ");
99         }
100     }
101 
printTypeArgs(final NodeWithTypeArguments<?> nodeWithTypeArguments, final Void arg)102     private void printTypeArgs(final NodeWithTypeArguments<?> nodeWithTypeArguments, final Void arg) {
103         NodeList<Type> typeArguments = nodeWithTypeArguments.getTypeArguments().orElse(null);
104         if (!isNullOrEmpty(typeArguments)) {
105             printer.print("<");
106             for (final Iterator<Type> i = typeArguments.iterator(); i.hasNext(); ) {
107                 final Type t = i.next();
108                 t.accept(this, arg);
109                 if (i.hasNext()) {
110                     printer.print(", ");
111                 }
112             }
113             printer.print(">");
114         }
115     }
116 
printTypeParameters(final NodeList<TypeParameter> args, final Void arg)117     private void printTypeParameters(final NodeList<TypeParameter> args, final Void arg) {
118         if (!isNullOrEmpty(args)) {
119             printer.print("<");
120             for (final Iterator<TypeParameter> i = args.iterator(); i.hasNext(); ) {
121                 final TypeParameter t = i.next();
122                 t.accept(this, arg);
123                 if (i.hasNext()) {
124                     printer.print(", ");
125                 }
126             }
127             printer.print(">");
128         }
129     }
130 
printArguments(final NodeList<Expression> args, final Void arg)131     private void printArguments(final NodeList<Expression> args, final Void arg) {
132         printer.print("(");
133         if (!isNullOrEmpty(args)) {
134             for (final Iterator<Expression> i = args.iterator(); i.hasNext(); ) {
135                 final Expression e = i.next();
136                 e.accept(this, arg);
137                 if (i.hasNext()) {
138                     printer.print(", ");
139                 }
140             }
141         }
142         printer.print(")");
143     }
144 
printJavaComment(final Comment javacomment, final Void arg)145     private void printJavaComment(final Comment javacomment, final Void arg) {
146         if (javacomment != null) {
147             javacomment.accept(this, arg);
148         }
149     }
150 
151     @Override
visit(final CompilationUnit n, final Void arg)152     public void visit(final CompilationUnit n, final Void arg) {
153         printJavaComment(n.getComment(), arg);
154 
155         if (n.getPackageDeclaration().isPresent()) {
156             n.getPackageDeclaration().get().accept(this, arg);
157         }
158 
159         n.getImports().accept(this, arg);
160         if (!n.getImports().isEmpty()) {
161             printer.println();
162         }
163 
164         for (final Iterator<TypeDeclaration<?>> i = n.getTypes().iterator(); i.hasNext(); ) {
165             i.next().accept(this, arg);
166             printer.println();
167             if (i.hasNext()) {
168                 printer.println();
169             }
170         }
171 
172         printOrphanCommentsEnding(n);
173     }
174 
175     @Override
visit(final PackageDeclaration n, final Void arg)176     public void visit(final PackageDeclaration n, final Void arg) {
177         printJavaComment(n.getComment(), arg);
178         printAnnotations(n.getAnnotations(), false, arg);
179         printer.print("package ");
180         n.getName().accept(this, arg);
181         printer.println(";");
182         printer.println();
183 
184         printOrphanCommentsEnding(n);
185     }
186 
187     @Override
visit(final NameExpr n, final Void arg)188     public void visit(final NameExpr n, final Void arg) {
189         printJavaComment(n.getComment(), arg);
190         n.getName().accept(this, arg);
191 
192         printOrphanCommentsEnding(n);
193     }
194 
195     @Override
visit(final Name n, final Void arg)196     public void visit(final Name n, final Void arg) {
197         printJavaComment(n.getComment(), arg);
198         if (n.getQualifier().isPresent()) {
199             n.getQualifier().get().accept(this, arg);
200             printer.print(".");
201         }
202         printer.print(n.getIdentifier());
203 
204         printOrphanCommentsEnding(n);
205     }
206 
207     @Override
visit(SimpleName n, Void arg)208     public void visit(SimpleName n, Void arg) {
209         printer.print(n.getIdentifier());
210     }
211 
212     @Override
visit(final ClassOrInterfaceDeclaration n, final Void arg)213     public void visit(final ClassOrInterfaceDeclaration n, final Void arg) {
214         printJavaComment(n.getComment(), arg);
215         printMemberAnnotations(n.getAnnotations(), arg);
216         printModifiers(n.getModifiers());
217 
218         if (n.isInterface()) {
219             printer.print("interface ");
220         } else {
221             printer.print("class ");
222         }
223 
224         n.getName().accept(this, arg);
225 
226         printTypeParameters(n.getTypeParameters(), arg);
227 
228         if (!n.getExtendedTypes().isEmpty()) {
229             printer.print(" extends ");
230             for (final Iterator<ClassOrInterfaceType> i = n.getExtendedTypes().iterator(); i.hasNext(); ) {
231                 final ClassOrInterfaceType c = i.next();
232                 c.accept(this, arg);
233                 if (i.hasNext()) {
234                     printer.print(", ");
235                 }
236             }
237         }
238 
239         if (!n.getImplementedTypes().isEmpty()) {
240             printer.print(" implements ");
241             for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) {
242                 final ClassOrInterfaceType c = i.next();
243                 c.accept(this, arg);
244                 if (i.hasNext()) {
245                     printer.print(", ");
246                 }
247             }
248         }
249 
250         printer.println(" {");
251         printer.indent();
252         if (!isNullOrEmpty(n.getMembers())) {
253             printMembers(n.getMembers(), arg);
254         }
255 
256         printOrphanCommentsEnding(n);
257 
258         printer.unindent();
259         printer.print("}");
260     }
261 
262     @Override
visit(final JavadocComment n, final Void arg)263     public void visit(final JavadocComment n, final Void arg) {
264         printer.print("/**");
265         printer.print(n.getContent());
266         printer.println("*/");
267     }
268 
269     @Override
visit(final ClassOrInterfaceType n, final Void arg)270     public void visit(final ClassOrInterfaceType n, final Void arg) {
271         printJavaComment(n.getComment(), arg);
272 
273         if (n.getScope().isPresent()) {
274             n.getScope().get().accept(this, arg);
275             printer.print(".");
276         }
277         for (AnnotationExpr ae : n.getAnnotations()) {
278             ae.accept(this, arg);
279             printer.print(" ");
280         }
281 
282         n.getName().accept(this, arg);
283 
284         if (n.isUsingDiamondOperator()) {
285             printer.print("<>");
286         } else {
287             printTypeArgs(n, arg);
288         }
289     }
290 
291     @Override
visit(final TypeParameter n, final Void arg)292     public void visit(final TypeParameter n, final Void arg) {
293         printJavaComment(n.getComment(), arg);
294         for (AnnotationExpr ann : n.getAnnotations()) {
295             ann.accept(this, arg);
296             printer.print(" ");
297         }
298         n.getName().accept(this, arg);
299         if (!isNullOrEmpty(n.getTypeBound())) {
300             printer.print(" extends ");
301             for (final Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext(); ) {
302                 final ClassOrInterfaceType c = i.next();
303                 c.accept(this, arg);
304                 if (i.hasNext()) {
305                     printer.print(" & ");
306                 }
307             }
308         }
309     }
310 
311     @Override
visit(final PrimitiveType n, final Void arg)312     public void visit(final PrimitiveType n, final Void arg) {
313         printJavaComment(n.getComment(), arg);
314         printAnnotations(n.getAnnotations(), true, arg);
315         printer.print(n.getType().asString());
316     }
317 
318     @Override
visit(final ArrayType n, final Void arg)319     public void visit(final ArrayType n, final Void arg) {
320         final List<ArrayType> arrayTypeBuffer = new LinkedList<>();
321         Type type = n;
322         while (type instanceof ArrayType) {
323             final ArrayType arrayType = (ArrayType) type;
324             arrayTypeBuffer.add(arrayType);
325             type = arrayType.getComponentType();
326         }
327 
328         type.accept(this, arg);
329         for (ArrayType arrayType : arrayTypeBuffer) {
330             printAnnotations(arrayType.getAnnotations(), true, arg);
331             printer.print("[]");
332         }
333     }
334 
335     @Override
visit(final ArrayCreationLevel n, final Void arg)336     public void visit(final ArrayCreationLevel n, final Void arg) {
337         printAnnotations(n.getAnnotations(), true, arg);
338         printer.print("[");
339         if (n.getDimension().isPresent()) {
340             n.getDimension().get().accept(this, arg);
341         }
342         printer.print("]");
343     }
344 
345     @Override
visit(final IntersectionType n, final Void arg)346     public void visit(final IntersectionType n, final Void arg) {
347         printJavaComment(n.getComment(), arg);
348         printAnnotations(n.getAnnotations(), false, arg);
349         boolean isFirst = true;
350         for (ReferenceType element : n.getElements()) {
351             element.accept(this, arg);
352             if (isFirst) {
353                 isFirst = false;
354             } else {
355                 printer.print(" & ");
356             }
357         }
358     }
359 
360     @Override
visit(final UnionType n, final Void arg)361     public void visit(final UnionType n, final Void arg) {
362         printJavaComment(n.getComment(), arg);
363         printAnnotations(n.getAnnotations(), true, arg);
364         boolean isFirst = true;
365         for (ReferenceType element : n.getElements()) {
366             if (isFirst) {
367                 isFirst = false;
368             } else {
369                 printer.print(" | ");
370             }
371             element.accept(this, arg);
372         }
373     }
374 
375     @Override
visit(final WildcardType n, final Void arg)376     public void visit(final WildcardType n, final Void arg) {
377         printJavaComment(n.getComment(), arg);
378         printAnnotations(n.getAnnotations(), false, arg);
379         printer.print("?");
380         if (n.getExtendedTypes().isPresent()) {
381             printer.print(" extends ");
382             n.getExtendedTypes().get().accept(this, arg);
383         }
384         if (n.getSuperTypes().isPresent()) {
385             printer.print(" super ");
386             n.getSuperTypes().get().accept(this, arg);
387         }
388     }
389 
390     @Override
visit(final UnknownType n, final Void arg)391     public void visit(final UnknownType n, final Void arg) {
392         // Nothing to print
393     }
394 
395     @Override
visit(final FieldDeclaration n, final Void arg)396     public void visit(final FieldDeclaration n, final Void arg) {
397         printOrphanCommentsBeforeThisChildNode(n);
398 
399         printJavaComment(n.getComment(), arg);
400         printMemberAnnotations(n.getAnnotations(), arg);
401         printModifiers(n.getModifiers());
402         if (!n.getVariables().isEmpty()) {
403             n.getMaximumCommonType().accept(this, arg);
404         }
405 
406         printer.print(" ");
407         for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) {
408             final VariableDeclarator var = i.next();
409             var.accept(this, arg);
410             if (i.hasNext()) {
411                 printer.print(", ");
412             }
413         }
414 
415         printer.print(";");
416     }
417 
418     @Override
visit(final VariableDeclarator n, final Void arg)419     public void visit(final VariableDeclarator n, final Void arg) {
420         printJavaComment(n.getComment(), arg);
421         n.getName().accept(this, arg);
422 
423         Type commonType = n.getAncestorOfType(NodeWithVariables.class).get().getMaximumCommonType();
424 
425         Type type = n.getType();
426 
427         ArrayType arrayType = null;
428 
429         for (int i = commonType.getArrayLevel(); i < type.getArrayLevel(); i++) {
430             if (arrayType == null) {
431                 arrayType = (ArrayType) type;
432             } else {
433                 arrayType = (ArrayType) arrayType.getComponentType();
434             }
435             printAnnotations(arrayType.getAnnotations(), true, arg);
436             printer.print("[]");
437         }
438 
439         if (n.getInitializer().isPresent()) {
440             printer.print(" = ");
441             n.getInitializer().get().accept(this, arg);
442         }
443     }
444 
445     @Override
visit(final ArrayInitializerExpr n, final Void arg)446     public void visit(final ArrayInitializerExpr n, final Void arg) {
447         printJavaComment(n.getComment(), arg);
448         printer.print("{");
449         if (!isNullOrEmpty(n.getValues())) {
450             printer.print(" ");
451             for (final Iterator<Expression> i = n.getValues().iterator(); i.hasNext(); ) {
452                 final Expression expr = i.next();
453                 expr.accept(this, arg);
454                 if (i.hasNext()) {
455                     printer.print(", ");
456                 }
457             }
458             printer.print(" ");
459         }
460         printer.print("}");
461     }
462 
463     @Override
visit(final VoidType n, final Void arg)464     public void visit(final VoidType n, final Void arg) {
465         printJavaComment(n.getComment(), arg);
466         printAnnotations(n.getAnnotations(), false, arg);
467         printer.print("void");
468     }
469 
470     @Override
visit(final ArrayAccessExpr n, final Void arg)471     public void visit(final ArrayAccessExpr n, final Void arg) {
472         printJavaComment(n.getComment(), arg);
473         n.getName().accept(this, arg);
474         printer.print("[");
475         n.getIndex().accept(this, arg);
476         printer.print("]");
477     }
478 
479     @Override
visit(final ArrayCreationExpr n, final Void arg)480     public void visit(final ArrayCreationExpr n, final Void arg) {
481         printJavaComment(n.getComment(), arg);
482         printer.print("new ");
483         n.getElementType().accept(this, arg);
484         for (ArrayCreationLevel level : n.getLevels()) {
485             level.accept(this, arg);
486         }
487         if (n.getInitializer().isPresent()) {
488             printer.print(" ");
489             n.getInitializer().get().accept(this, arg);
490         }
491     }
492 
493     @Override
visit(final AssignExpr n, final Void arg)494     public void visit(final AssignExpr n, final Void arg) {
495         printJavaComment(n.getComment(), arg);
496         n.getTarget().accept(this, arg);
497         printer.print(" ");
498         printer.print(n.getOperator().asString());
499         printer.print(" ");
500         n.getValue().accept(this, arg);
501     }
502 
503     @Override
visit(final BinaryExpr n, final Void arg)504     public void visit(final BinaryExpr n, final Void arg) {
505         printJavaComment(n.getComment(), arg);
506         n.getLeft().accept(this, arg);
507         printer.print(" ");
508         printer.print(n.getOperator().asString());
509         printer.print(" ");
510         n.getRight().accept(this, arg);
511     }
512 
513     @Override
visit(final CastExpr n, final Void arg)514     public void visit(final CastExpr n, final Void arg) {
515         printJavaComment(n.getComment(), arg);
516         printer.print("(");
517         n.getType().accept(this, arg);
518         printer.print(") ");
519         n.getExpression().accept(this, arg);
520     }
521 
522     @Override
visit(final ClassExpr n, final Void arg)523     public void visit(final ClassExpr n, final Void arg) {
524         printJavaComment(n.getComment(), arg);
525         n.getType().accept(this, arg);
526         printer.print(".class");
527     }
528 
529     @Override
visit(final ConditionalExpr n, final Void arg)530     public void visit(final ConditionalExpr n, final Void arg) {
531         printJavaComment(n.getComment(), arg);
532         n.getCondition().accept(this, arg);
533         printer.print(" ? ");
534         n.getThenExpr().accept(this, arg);
535         printer.print(" : ");
536         n.getElseExpr().accept(this, arg);
537     }
538 
539     @Override
visit(final EnclosedExpr n, final Void arg)540     public void visit(final EnclosedExpr n, final Void arg) {
541         printJavaComment(n.getComment(), arg);
542         printer.print("(");
543         if (n.getInner().isPresent()) {
544             n.getInner().get().accept(this, arg);
545         }
546         printer.print(")");
547     }
548 
549     @Override
visit(final FieldAccessExpr n, final Void arg)550     public void visit(final FieldAccessExpr n, final Void arg) {
551         printJavaComment(n.getComment(), arg);
552         if (n.getScope().isPresent())
553             n.getScope().get().accept(this, arg);
554         printer.print(".");
555         n.getName().accept(this, arg);
556     }
557 
558     @Override
visit(final InstanceOfExpr n, final Void arg)559     public void visit(final InstanceOfExpr n, final Void arg) {
560         printJavaComment(n.getComment(), arg);
561         n.getExpression().accept(this, arg);
562         printer.print(" instanceof ");
563         n.getType().accept(this, arg);
564     }
565 
566     @Override
visit(final CharLiteralExpr n, final Void arg)567     public void visit(final CharLiteralExpr n, final Void arg) {
568         printJavaComment(n.getComment(), arg);
569         printer.print("'");
570         printer.print(n.getValue());
571         printer.print("'");
572     }
573 
574     @Override
visit(final DoubleLiteralExpr n, final Void arg)575     public void visit(final DoubleLiteralExpr n, final Void arg) {
576         printJavaComment(n.getComment(), arg);
577         printer.print(n.getValue());
578     }
579 
580     @Override
visit(final IntegerLiteralExpr n, final Void arg)581     public void visit(final IntegerLiteralExpr n, final Void arg) {
582         printJavaComment(n.getComment(), arg);
583         printer.print(n.getValue());
584     }
585 
586     @Override
visit(final LongLiteralExpr n, final Void arg)587     public void visit(final LongLiteralExpr n, final Void arg) {
588         printJavaComment(n.getComment(), arg);
589         printer.print(n.getValue());
590     }
591 
592     @Override
visit(final StringLiteralExpr n, final Void arg)593     public void visit(final StringLiteralExpr n, final Void arg) {
594         printJavaComment(n.getComment(), arg);
595         printer.print("\"");
596         printer.print(n.getValue());
597         printer.print("\"");
598     }
599 
600     @Override
visit(final BooleanLiteralExpr n, final Void arg)601     public void visit(final BooleanLiteralExpr n, final Void arg) {
602         printJavaComment(n.getComment(), arg);
603         printer.print(String.valueOf(n.getValue()));
604     }
605 
606     @Override
visit(final NullLiteralExpr n, final Void arg)607     public void visit(final NullLiteralExpr n, final Void arg) {
608         printJavaComment(n.getComment(), arg);
609         printer.print("null");
610     }
611 
612     @Override
visit(final ThisExpr n, final Void arg)613     public void visit(final ThisExpr n, final Void arg) {
614         printJavaComment(n.getComment(), arg);
615         if (n.getClassExpr().isPresent()) {
616             n.getClassExpr().get().accept(this, arg);
617             printer.print(".");
618         }
619         printer.print("this");
620     }
621 
622     @Override
visit(final SuperExpr n, final Void arg)623     public void visit(final SuperExpr n, final Void arg) {
624         printJavaComment(n.getComment(), arg);
625         if (n.getClassExpr().isPresent()) {
626             n.getClassExpr().get().accept(this, arg);
627             printer.print(".");
628         }
629         printer.print("super");
630     }
631 
632     @Override
visit(final MethodCallExpr n, final Void arg)633     public void visit(final MethodCallExpr n, final Void arg) {
634         printJavaComment(n.getComment(), arg);
635         if (n.getScope().isPresent()) {
636             n.getScope().get().accept(this, arg);
637             printer.print(".");
638         }
639         printTypeArgs(n, arg);
640         n.getName().accept(this, arg);
641         printArguments(n.getArguments(), arg);
642     }
643 
644     @Override
visit(final ObjectCreationExpr n, final Void arg)645     public void visit(final ObjectCreationExpr n, final Void arg) {
646         printJavaComment(n.getComment(), arg);
647         if (n.getScope().isPresent()) {
648             n.getScope().get().accept(this, arg);
649             printer.print(".");
650         }
651 
652         printer.print("new ");
653 
654         printTypeArgs(n, arg);
655         if (!isNullOrEmpty(n.getTypeArguments().orElse(null))) {
656             printer.print(" ");
657         }
658 
659         n.getType().accept(this, arg);
660 
661         printArguments(n.getArguments(), arg);
662 
663         if (n.getAnonymousClassBody().isPresent()) {
664             printer.println(" {");
665             printer.indent();
666             printMembers(n.getAnonymousClassBody().get(), arg);
667             printer.unindent();
668             printer.print("}");
669         }
670     }
671 
672     @Override
visit(final UnaryExpr n, final Void arg)673     public void visit(final UnaryExpr n, final Void arg) {
674         printJavaComment(n.getComment(), arg);
675         if (n.getOperator().isPrefix()) {
676             printer.print(n.getOperator().asString());
677         }
678 
679         n.getExpression().accept(this, arg);
680 
681         if (n.getOperator().isPostfix()) {
682             printer.print(n.getOperator().asString());
683         }
684     }
685 
686     @Override
visit(final ConstructorDeclaration n, final Void arg)687     public void visit(final ConstructorDeclaration n, final Void arg) {
688         printJavaComment(n.getComment(), arg);
689         printMemberAnnotations(n.getAnnotations(), arg);
690         printModifiers(n.getModifiers());
691 
692         printTypeParameters(n.getTypeParameters(), arg);
693         if (n.isGeneric()) {
694             printer.print(" ");
695         }
696         n.getName().accept(this, arg);
697 
698         printer.print("(");
699         if (!n.getParameters().isEmpty()) {
700             for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) {
701                 final Parameter p = i.next();
702                 p.accept(this, arg);
703                 if (i.hasNext()) {
704                     printer.print(", ");
705                 }
706             }
707         }
708         printer.print(")");
709 
710         if (!isNullOrEmpty(n.getThrownExceptions())) {
711             printer.print(" throws ");
712             for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) {
713                 final ReferenceType name = i.next();
714                 name.accept(this, arg);
715                 if (i.hasNext()) {
716                     printer.print(", ");
717                 }
718             }
719         }
720         printer.print(" ");
721         n.getBody().accept(this, arg);
722     }
723 
724     @Override
visit(final MethodDeclaration n, final Void arg)725     public void visit(final MethodDeclaration n, final Void arg) {
726         printOrphanCommentsBeforeThisChildNode(n);
727 
728         printJavaComment(n.getComment(), arg);
729         printMemberAnnotations(n.getAnnotations(), arg);
730         printModifiers(n.getModifiers());
731         if (n.isDefault()) {
732             printer.print("default ");
733         }
734         printTypeParameters(n.getTypeParameters(), arg);
735         if (!isNullOrEmpty(n.getTypeParameters())) {
736             printer.print(" ");
737         }
738 
739         n.getType().accept(this, arg);
740         printer.print(" ");
741         n.getName().accept(this, arg);
742 
743         printer.print("(");
744         if (!isNullOrEmpty(n.getParameters())) {
745             for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) {
746                 final Parameter p = i.next();
747                 p.accept(this, arg);
748                 if (i.hasNext()) {
749                     printer.print(", ");
750                 }
751             }
752         }
753         printer.print(")");
754 
755         if (!isNullOrEmpty(n.getThrownExceptions())) {
756             printer.print(" throws ");
757             for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) {
758                 final ReferenceType name = i.next();
759                 name.accept(this, arg);
760                 if (i.hasNext()) {
761                     printer.print(", ");
762                 }
763             }
764         }
765         if (!n.getBody().isPresent()) {
766             printer.print(";");
767         } else {
768             printer.print(" ");
769             n.getBody().get().accept(this, arg);
770         }
771     }
772 
773     @Override
visit(final Parameter n, final Void arg)774     public void visit(final Parameter n, final Void arg) {
775         printJavaComment(n.getComment(), arg);
776         printAnnotations(n.getAnnotations(), false, arg);
777         printModifiers(n.getModifiers());
778         if (n.getType() != null) {
779             n.getType().accept(this, arg);
780         }
781         if (n.isVarArgs()) {
782             printer.print("...");
783         }
784         printer.print(" ");
785         n.getName().accept(this, arg);
786     }
787 
788     @Override
visit(final ExplicitConstructorInvocationStmt n, final Void arg)789     public void visit(final ExplicitConstructorInvocationStmt n, final Void arg) {
790         printJavaComment(n.getComment(), arg);
791         if (n.isThis()) {
792             printTypeArgs(n, arg);
793             printer.print("this");
794         } else {
795             if (n.getExpression().isPresent()) {
796                 n.getExpression().get().accept(this, arg);
797                 printer.print(".");
798             }
799             printTypeArgs(n, arg);
800             printer.print("super");
801         }
802         printArguments(n.getArguments(), arg);
803         printer.print(";");
804     }
805 
806     @Override
visit(final VariableDeclarationExpr n, final Void arg)807     public void visit(final VariableDeclarationExpr n, final Void arg) {
808         printJavaComment(n.getComment(), arg);
809         printAnnotations(n.getAnnotations(), false, arg);
810         printModifiers(n.getModifiers());
811 
812         if (!n.getVariables().isEmpty()) {
813             n.getMaximumCommonType().accept(this, arg);
814         }
815         printer.print(" ");
816 
817         for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) {
818             final VariableDeclarator v = i.next();
819             v.accept(this, arg);
820             if (i.hasNext()) {
821                 printer.print(", ");
822             }
823         }
824     }
825 
826     @Override
visit(final LocalClassDeclarationStmt n, final Void arg)827     public void visit(final LocalClassDeclarationStmt n, final Void arg) {
828         printJavaComment(n.getComment(), arg);
829         n.getClassDeclaration().accept(this, arg);
830     }
831 
832     @Override
visit(final AssertStmt n, final Void arg)833     public void visit(final AssertStmt n, final Void arg) {
834         printJavaComment(n.getComment(), arg);
835         printer.print("assert ");
836         n.getCheck().accept(this, arg);
837         if (n.getMessage().isPresent()) {
838             printer.print(" : ");
839             n.getMessage().get().accept(this, arg);
840         }
841         printer.print(";");
842     }
843 
844     @Override
visit(final BlockStmt n, final Void arg)845     public void visit(final BlockStmt n, final Void arg) {
846         printOrphanCommentsBeforeThisChildNode(n);
847         printJavaComment(n.getComment(), arg);
848         printer.println("{");
849         if (n.getStatements() != null) {
850             printer.indent();
851             for (final Statement s : n.getStatements()) {
852                 s.accept(this, arg);
853                 printer.println();
854             }
855             printer.unindent();
856         }
857         printOrphanCommentsEnding(n);
858         printer.print("}");
859 
860     }
861 
862     @Override
visit(final LabeledStmt n, final Void arg)863     public void visit(final LabeledStmt n, final Void arg) {
864         printJavaComment(n.getComment(), arg);
865         n.getLabel().accept(this, arg);
866         printer.print(": ");
867         n.getStatement().accept(this, arg);
868     }
869 
870     @Override
visit(final EmptyStmt n, final Void arg)871     public void visit(final EmptyStmt n, final Void arg) {
872         printJavaComment(n.getComment(), arg);
873         printer.print(";");
874     }
875 
876     @Override
visit(final ExpressionStmt n, final Void arg)877     public void visit(final ExpressionStmt n, final Void arg) {
878         printOrphanCommentsBeforeThisChildNode(n);
879         printJavaComment(n.getComment(), arg);
880         n.getExpression().accept(this, arg);
881         printer.print(";");
882     }
883 
884     @Override
visit(final SwitchStmt n, final Void arg)885     public void visit(final SwitchStmt n, final Void arg) {
886         printJavaComment(n.getComment(), arg);
887         printer.print("switch(");
888         n.getSelector().accept(this, arg);
889         printer.println(") {");
890         if (n.getEntries() != null) {
891             printer.indent();
892             for (final SwitchEntryStmt e : n.getEntries()) {
893                 e.accept(this, arg);
894             }
895             printer.unindent();
896         }
897         printer.print("}");
898 
899     }
900 
901     @Override
visit(final SwitchEntryStmt n, final Void arg)902     public void visit(final SwitchEntryStmt n, final Void arg) {
903         printJavaComment(n.getComment(), arg);
904         if (n.getLabel().isPresent()) {
905             printer.print("case ");
906             n.getLabel().get().accept(this, arg);
907             printer.print(":");
908         } else {
909             printer.print("default:");
910         }
911         printer.println();
912         printer.indent();
913         if (n.getStatements() != null) {
914             for (final Statement s : n.getStatements()) {
915                 s.accept(this, arg);
916                 printer.println();
917             }
918         }
919         printer.unindent();
920     }
921 
922     @Override
visit(final BreakStmt n, final Void arg)923     public void visit(final BreakStmt n, final Void arg) {
924         printJavaComment(n.getComment(), arg);
925         printer.print("break");
926         n.getLabel().ifPresent(l -> printer.print(" ").print(l.getIdentifier()));
927         printer.print(";");
928     }
929 
930     @Override
visit(final ReturnStmt n, final Void arg)931     public void visit(final ReturnStmt n, final Void arg) {
932         printJavaComment(n.getComment(), arg);
933         printer.print("return");
934         if (n.getExpression().isPresent()) {
935             printer.print(" ");
936             n.getExpression().get().accept(this, arg);
937         }
938         printer.print(";");
939     }
940 
941     @Override
visit(final EnumDeclaration n, final Void arg)942     public void visit(final EnumDeclaration n, final Void arg) {
943         printJavaComment(n.getComment(), arg);
944         printMemberAnnotations(n.getAnnotations(), arg);
945         printModifiers(n.getModifiers());
946 
947         printer.print("enum ");
948         n.getName().accept(this, arg);
949 
950         if (!n.getImplementedTypes().isEmpty()) {
951             printer.print(" implements ");
952             for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) {
953                 final ClassOrInterfaceType c = i.next();
954                 c.accept(this, arg);
955                 if (i.hasNext()) {
956                     printer.print(", ");
957                 }
958             }
959         }
960 
961         printer.println(" {");
962         printer.indent();
963         if (n.getEntries() != null) {
964             printer.println();
965             for (final Iterator<EnumConstantDeclaration> i = n.getEntries().iterator(); i.hasNext(); ) {
966                 final EnumConstantDeclaration e = i.next();
967                 e.accept(this, arg);
968                 if (i.hasNext()) {
969                     printer.print(", ");
970                 }
971             }
972         }
973         if (!n.getMembers().isEmpty()) {
974             printer.println(";");
975             printMembers(n.getMembers(), arg);
976         } else {
977             if (!n.getEntries().isEmpty()) {
978                 printer.println();
979             }
980         }
981         printer.unindent();
982         printer.print("}");
983     }
984 
985     @Override
visit(final EnumConstantDeclaration n, final Void arg)986     public void visit(final EnumConstantDeclaration n, final Void arg) {
987         printJavaComment(n.getComment(), arg);
988         printMemberAnnotations(n.getAnnotations(), arg);
989         n.getName().accept(this, arg);
990 
991         if (!n.getArguments().isEmpty()) {
992             printArguments(n.getArguments(), arg);
993         }
994 
995         if (!n.getClassBody().isEmpty()) {
996             printer.println(" {");
997             printer.indent();
998             printMembers(n.getClassBody(), arg);
999             printer.unindent();
1000             printer.println("}");
1001         }
1002     }
1003 
1004     @Override
visit(final EmptyMemberDeclaration n, final Void arg)1005     public void visit(final EmptyMemberDeclaration n, final Void arg) {
1006         printJavaComment(n.getComment(), arg);
1007         printer.print(";");
1008     }
1009 
1010     @Override
visit(final InitializerDeclaration n, final Void arg)1011     public void visit(final InitializerDeclaration n, final Void arg) {
1012         printJavaComment(n.getComment(), arg);
1013         if (n.isStatic()) {
1014             printer.print("static ");
1015         }
1016         n.getBody().accept(this, arg);
1017     }
1018 
1019     @Override
visit(final IfStmt n, final Void arg)1020     public void visit(final IfStmt n, final Void arg) {
1021         printJavaComment(n.getComment(), arg);
1022         printer.print("if (");
1023         n.getCondition().accept(this, arg);
1024         final boolean thenBlock = n.getThenStmt() instanceof BlockStmt;
1025         if (thenBlock) // block statement should start on the same line
1026             printer.print(") ");
1027         else {
1028             printer.println(")");
1029             printer.indent();
1030         }
1031         n.getThenStmt().accept(this, arg);
1032         if (!thenBlock)
1033             printer.unindent();
1034         if (n.getElseStmt().isPresent()) {
1035             if (thenBlock)
1036                 printer.print(" ");
1037             else
1038                 printer.println();
1039             final boolean elseIf = n.getElseStmt().orElse(null) instanceof IfStmt;
1040             final boolean elseBlock = n.getElseStmt().orElse(null) instanceof BlockStmt;
1041             if (elseIf || elseBlock) // put chained if and start of block statement on a same level
1042                 printer.print("else ");
1043             else {
1044                 printer.println("else");
1045                 printer.indent();
1046             }
1047             if (n.getElseStmt().isPresent())
1048                 n.getElseStmt().get().accept(this, arg);
1049             if (!(elseIf || elseBlock))
1050                 printer.unindent();
1051         }
1052     }
1053 
1054     @Override
visit(final WhileStmt n, final Void arg)1055     public void visit(final WhileStmt n, final Void arg) {
1056         printJavaComment(n.getComment(), arg);
1057         printer.print("while (");
1058         n.getCondition().accept(this, arg);
1059         printer.print(") ");
1060         n.getBody().accept(this, arg);
1061     }
1062 
1063     @Override
visit(final ContinueStmt n, final Void arg)1064     public void visit(final ContinueStmt n, final Void arg) {
1065         printJavaComment(n.getComment(), arg);
1066         printer.print("continue");
1067         n.getLabel().ifPresent(l -> printer.print(" ").print(l.getIdentifier()));
1068         printer.print(";");
1069     }
1070 
1071     @Override
visit(final DoStmt n, final Void arg)1072     public void visit(final DoStmt n, final Void arg) {
1073         printJavaComment(n.getComment(), arg);
1074         printer.print("do ");
1075         n.getBody().accept(this, arg);
1076         printer.print(" while (");
1077         n.getCondition().accept(this, arg);
1078         printer.print(");");
1079     }
1080 
1081     @Override
visit(final ForeachStmt n, final Void arg)1082     public void visit(final ForeachStmt n, final Void arg) {
1083         printJavaComment(n.getComment(), arg);
1084         printer.print("for (");
1085         n.getVariable().accept(this, arg);
1086         printer.print(" : ");
1087         n.getIterable().accept(this, arg);
1088         printer.print(") ");
1089         n.getBody().accept(this, arg);
1090     }
1091 
1092     @Override
visit(final ForStmt n, final Void arg)1093     public void visit(final ForStmt n, final Void arg) {
1094         printJavaComment(n.getComment(), arg);
1095         printer.print("for (");
1096         if (n.getInitialization() != null) {
1097             for (final Iterator<Expression> i = n.getInitialization().iterator(); i.hasNext(); ) {
1098                 final Expression e = i.next();
1099                 e.accept(this, arg);
1100                 if (i.hasNext()) {
1101                     printer.print(", ");
1102                 }
1103             }
1104         }
1105         printer.print("; ");
1106         if (n.getCompare().isPresent()) {
1107             n.getCompare().get().accept(this, arg);
1108         }
1109         printer.print("; ");
1110         if (n.getUpdate() != null) {
1111             for (final Iterator<Expression> i = n.getUpdate().iterator(); i.hasNext(); ) {
1112                 final Expression e = i.next();
1113                 e.accept(this, arg);
1114                 if (i.hasNext()) {
1115                     printer.print(", ");
1116                 }
1117             }
1118         }
1119         printer.print(") ");
1120         n.getBody().accept(this, arg);
1121     }
1122 
1123     @Override
visit(final ThrowStmt n, final Void arg)1124     public void visit(final ThrowStmt n, final Void arg) {
1125         printJavaComment(n.getComment(), arg);
1126         printer.print("throw ");
1127         n.getExpression().accept(this, arg);
1128         printer.print(";");
1129     }
1130 
1131     @Override
visit(final SynchronizedStmt n, final Void arg)1132     public void visit(final SynchronizedStmt n, final Void arg) {
1133         printJavaComment(n.getComment(), arg);
1134         printer.print("synchronized (");
1135         n.getExpression().accept(this, arg);
1136         printer.print(") ");
1137         n.getBody().accept(this, arg);
1138     }
1139 
1140     @Override
visit(final TryStmt n, final Void arg)1141     public void visit(final TryStmt n, final Void arg) {
1142         printJavaComment(n.getComment(), arg);
1143         printer.print("try ");
1144         if (!n.getResources().isEmpty()) {
1145             printer.print("(");
1146             Iterator<VariableDeclarationExpr> resources = n.getResources().iterator();
1147             boolean first = true;
1148             while (resources.hasNext()) {
1149                 visit(resources.next(), arg);
1150                 if (resources.hasNext()) {
1151                     printer.print(";");
1152                     printer.println();
1153                     if (first) {
1154                         printer.indent();
1155                     }
1156                 }
1157                 first = false;
1158             }
1159             if (n.getResources().size() > 1) {
1160                 printer.unindent();
1161             }
1162             printer.print(") ");
1163         }
1164         if (n.getTryBlock().isPresent()) {
1165             n.getTryBlock().get().accept(this, arg);
1166         }
1167         for (final CatchClause c : n.getCatchClauses()) {
1168             c.accept(this, arg);
1169         }
1170         if (n.getFinallyBlock().isPresent()) {
1171             printer.print(" finally ");
1172             n.getFinallyBlock().get().accept(this, arg);
1173         }
1174     }
1175 
1176     @Override
visit(final CatchClause n, final Void arg)1177     public void visit(final CatchClause n, final Void arg) {
1178         printJavaComment(n.getComment(), arg);
1179         printer.print(" catch (");
1180         n.getParameter().accept(this, arg);
1181         printer.print(") ");
1182         n.getBody().accept(this, arg);
1183 
1184     }
1185 
1186     @Override
visit(final AnnotationDeclaration n, final Void arg)1187     public void visit(final AnnotationDeclaration n, final Void arg) {
1188         printJavaComment(n.getComment(), arg);
1189         printMemberAnnotations(n.getAnnotations(), arg);
1190         printModifiers(n.getModifiers());
1191 
1192         printer.print("@interface ");
1193         n.getName().accept(this, arg);
1194         printer.println(" {");
1195         printer.indent();
1196         if (n.getMembers() != null) {
1197             printMembers(n.getMembers(), arg);
1198         }
1199         printer.unindent();
1200         printer.print("}");
1201     }
1202 
1203     @Override
visit(final AnnotationMemberDeclaration n, final Void arg)1204     public void visit(final AnnotationMemberDeclaration n, final Void arg) {
1205         printJavaComment(n.getComment(), arg);
1206         printMemberAnnotations(n.getAnnotations(), arg);
1207         printModifiers(n.getModifiers());
1208 
1209         n.getType().accept(this, arg);
1210         printer.print(" ");
1211         n.getName().accept(this, arg);
1212         printer.print("()");
1213         if (n.getDefaultValue().isPresent()) {
1214             printer.print(" default ");
1215             n.getDefaultValue().get().accept(this, arg);
1216         }
1217         printer.print(";");
1218     }
1219 
1220     @Override
visit(final MarkerAnnotationExpr n, final Void arg)1221     public void visit(final MarkerAnnotationExpr n, final Void arg) {
1222         printJavaComment(n.getComment(), arg);
1223         printer.print("@");
1224         n.getName().accept(this, arg);
1225     }
1226 
1227     @Override
visit(final SingleMemberAnnotationExpr n, final Void arg)1228     public void visit(final SingleMemberAnnotationExpr n, final Void arg) {
1229         printJavaComment(n.getComment(), arg);
1230         printer.print("@");
1231         n.getName().accept(this, arg);
1232         printer.print("(");
1233         n.getMemberValue().accept(this, arg);
1234         printer.print(")");
1235     }
1236 
1237     @Override
visit(final NormalAnnotationExpr n, final Void arg)1238     public void visit(final NormalAnnotationExpr n, final Void arg) {
1239         printJavaComment(n.getComment(), arg);
1240         printer.print("@");
1241         n.getName().accept(this, arg);
1242         printer.print("(");
1243         if (n.getPairs() != null) {
1244             for (final Iterator<MemberValuePair> i = n.getPairs().iterator(); i.hasNext(); ) {
1245                 final MemberValuePair m = i.next();
1246                 m.accept(this, arg);
1247                 if (i.hasNext()) {
1248                     printer.print(", ");
1249                 }
1250             }
1251         }
1252         printer.print(")");
1253     }
1254 
1255     @Override
visit(final MemberValuePair n, final Void arg)1256     public void visit(final MemberValuePair n, final Void arg) {
1257         printJavaComment(n.getComment(), arg);
1258         n.getName().accept(this, arg);
1259         printer.print(" = ");
1260         n.getValue().accept(this, arg);
1261     }
1262 
1263     @Override
visit(final LineComment n, final Void arg)1264     public void visit(final LineComment n, final Void arg) {
1265         if (!configuration.isPrintComments()) {
1266             return;
1267         }
1268         printer.print("//");
1269         String tmp = n.getContent();
1270         tmp = tmp.replace('\r', ' ');
1271         tmp = tmp.replace('\n', ' ');
1272         printer.println(tmp);
1273     }
1274 
1275     @Override
visit(final BlockComment n, final Void arg)1276     public void visit(final BlockComment n, final Void arg) {
1277         if (!configuration.isPrintComments()) {
1278             return;
1279         }
1280         printer.print("/*").print(n.getContent()).println("*/");
1281     }
1282 
1283     @Override
visit(LambdaExpr n, Void arg)1284     public void visit(LambdaExpr n, Void arg) {
1285         printJavaComment(n.getComment(), arg);
1286 
1287         final NodeList<Parameter> parameters = n.getParameters();
1288         final boolean printPar = n.isEnclosingParameters();
1289 
1290         if (printPar) {
1291             printer.print("(");
1292         }
1293         for (Iterator<Parameter> i = parameters.iterator(); i.hasNext(); ) {
1294             Parameter p = i.next();
1295             p.accept(this, arg);
1296             if (i.hasNext()) {
1297                 printer.print(", ");
1298             }
1299         }
1300         if (printPar) {
1301             printer.print(")");
1302         }
1303 
1304         printer.print(" -> ");
1305         final Statement body = n.getBody();
1306         if (body instanceof ExpressionStmt) {
1307             // Print the expression directly
1308             ((ExpressionStmt) body).getExpression().accept(this, arg);
1309         } else {
1310             body.accept(this, arg);
1311         }
1312     }
1313 
1314     @Override
visit(MethodReferenceExpr n, Void arg)1315     public void visit(MethodReferenceExpr n, Void arg) {
1316         printJavaComment(n.getComment(), arg);
1317         Expression scope = n.getScope();
1318         String identifier = n.getIdentifier();
1319         if (scope != null) {
1320             n.getScope().accept(this, arg);
1321         }
1322 
1323         printer.print("::");
1324         printTypeArgs(n, arg);
1325         if (identifier != null) {
1326             printer.print(identifier);
1327         }
1328 
1329     }
1330 
1331     @Override
visit(TypeExpr n, Void arg)1332     public void visit(TypeExpr n, Void arg) {
1333         printJavaComment(n.getComment(), arg);
1334         if (n.getType() != null) {
1335             n.getType().accept(this, arg);
1336         }
1337     }
1338 
1339     @Override
visit(NodeList n, Void arg)1340     public void visit(NodeList n, Void arg) {
1341         for (Object node : n) {
1342             ((Node) node).accept(this, arg);
1343         }
1344     }
1345 
1346     @Override
visit(final ImportDeclaration n, final Void arg)1347     public void visit(final ImportDeclaration n, final Void arg) {
1348         printJavaComment(n.getComment(), arg);
1349         printer.print("import ");
1350         if (n.isStatic()) {
1351             printer.print("static ");
1352         }
1353         n.getName().accept(this, arg);
1354         if (n.isAsterisk()) {
1355             printer.print(".*");
1356         }
1357         printer.println(";");
1358 
1359         printOrphanCommentsEnding(n);
1360     }
1361 
printOrphanCommentsBeforeThisChildNode(final Node node)1362     private void printOrphanCommentsBeforeThisChildNode(final Node node) {
1363         if (node instanceof Comment) return;
1364 
1365         Node parent = node.getParentNode().orElse(null);
1366         if (parent == null) return;
1367         List<Node> everything = new LinkedList<>();
1368         everything.addAll(parent.getChildNodes());
1369         sortByBeginPosition(everything);
1370         int positionOfTheChild = -1;
1371         for (int i = 0; i < everything.size(); i++) {
1372             if (everything.get(i) == node) positionOfTheChild = i;
1373         }
1374         if (positionOfTheChild == -1) {
1375             throw new AssertionError("I am not a child of my parent.");
1376         }
1377         int positionOfPreviousChild = -1;
1378         for (int i = positionOfTheChild - 1; i >= 0 && positionOfPreviousChild == -1; i--) {
1379             if (!(everything.get(i) instanceof Comment)) positionOfPreviousChild = i;
1380         }
1381         for (int i = positionOfPreviousChild + 1; i < positionOfTheChild; i++) {
1382             Node nodeToPrint = everything.get(i);
1383             if (!(nodeToPrint instanceof Comment))
1384                 throw new RuntimeException(
1385                         "Expected comment, instead " + nodeToPrint.getClass() + ". Position of previous child: "
1386                                 + positionOfPreviousChild + ", position of child " + positionOfTheChild);
1387             nodeToPrint.accept(this, null);
1388         }
1389     }
1390 
printOrphanCommentsEnding(final Node node)1391     private void printOrphanCommentsEnding(final Node node) {
1392         List<Node> everything = new LinkedList<>();
1393         everything.addAll(node.getChildNodes());
1394         sortByBeginPosition(everything);
1395         if (everything.isEmpty()) {
1396             return;
1397         }
1398 
1399         int commentsAtEnd = 0;
1400         boolean findingComments = true;
1401         while (findingComments && commentsAtEnd < everything.size()) {
1402             Node last = everything.get(everything.size() - 1 - commentsAtEnd);
1403             findingComments = (last instanceof Comment);
1404             if (findingComments) {
1405                 commentsAtEnd++;
1406             }
1407         }
1408         for (int i = 0; i < commentsAtEnd; i++) {
1409             everything.get(everything.size() - commentsAtEnd + i).accept(this, null);
1410         }
1411     }
1412 
1413 }
1414