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.modules.*; 32 import com.github.javaparser.ast.nodeTypes.*; 33 import com.github.javaparser.ast.stmt.*; 34 import com.github.javaparser.ast.type.*; 35 import com.github.javaparser.ast.visitor.Visitable; 36 import com.github.javaparser.ast.visitor.VoidVisitor; 37 38 import java.util.*; 39 import java.util.concurrent.atomic.AtomicBoolean; 40 41 import static com.github.javaparser.ast.Node.Parsedness.UNPARSABLE; 42 import static com.github.javaparser.utils.PositionUtils.sortByBeginPosition; 43 import static com.github.javaparser.utils.Utils.*; 44 import static java.util.Comparator.comparingInt; 45 import static java.util.stream.Collectors.joining; 46 47 /** 48 * Outputs the AST as formatted Java source code. 49 * 50 * @author Julio Vilmar Gesser 51 */ 52 public class PrettyPrintVisitor implements VoidVisitor<Void> { 53 protected final PrettyPrinterConfiguration configuration; 54 protected final SourcePrinter printer; 55 PrettyPrintVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration)56 public PrettyPrintVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration) { 57 configuration = prettyPrinterConfiguration; 58 printer = new SourcePrinter(configuration); 59 } 60 61 /** 62 * @deprecated use toString() 63 */ 64 @Deprecated getSource()65 public String getSource() { 66 return printer.toString(); 67 } 68 69 @Override toString()70 public String toString() { 71 return printer.toString(); 72 } 73 printModifiers(final NodeList<Modifier> modifiers)74 private void printModifiers(final NodeList<Modifier> modifiers) { 75 if (modifiers.size() > 0) { 76 printer.print(modifiers.stream().map(Modifier::getKeyword).map(Modifier.Keyword::asString).collect(joining(" ")) + " "); 77 } 78 } 79 printMembers(final NodeList<BodyDeclaration<?>> members, final Void arg)80 private void printMembers(final NodeList<BodyDeclaration<?>> members, final Void arg) { 81 for (final BodyDeclaration<?> member : members) { 82 printer.println(); 83 member.accept(this, arg); 84 printer.println(); 85 } 86 } 87 printMemberAnnotations(final NodeList<AnnotationExpr> annotations, final Void arg)88 private void printMemberAnnotations(final NodeList<AnnotationExpr> annotations, final Void arg) { 89 if (annotations.isEmpty()) { 90 return; 91 } 92 for (final AnnotationExpr a : annotations) { 93 a.accept(this, arg); 94 printer.println(); 95 } 96 } 97 printAnnotations(final NodeList<AnnotationExpr> annotations, boolean prefixWithASpace, final Void arg)98 private void printAnnotations(final NodeList<AnnotationExpr> annotations, boolean prefixWithASpace, 99 final Void arg) { 100 if (annotations.isEmpty()) { 101 return; 102 } 103 if (prefixWithASpace) { 104 printer.print(" "); 105 } 106 for (AnnotationExpr annotation : annotations) { 107 annotation.accept(this, arg); 108 printer.print(" "); 109 } 110 } 111 printTypeArgs(final NodeWithTypeArguments<?> nodeWithTypeArguments, final Void arg)112 private void printTypeArgs(final NodeWithTypeArguments<?> nodeWithTypeArguments, final Void arg) { 113 NodeList<Type> typeArguments = nodeWithTypeArguments.getTypeArguments().orElse(null); 114 if (!isNullOrEmpty(typeArguments)) { 115 printer.print("<"); 116 for (final Iterator<Type> i = typeArguments.iterator(); i.hasNext(); ) { 117 final Type t = i.next(); 118 t.accept(this, arg); 119 if (i.hasNext()) { 120 printer.print(", "); 121 } 122 } 123 printer.print(">"); 124 } 125 } 126 printTypeParameters(final NodeList<TypeParameter> args, final Void arg)127 private void printTypeParameters(final NodeList<TypeParameter> args, final Void arg) { 128 if (!isNullOrEmpty(args)) { 129 printer.print("<"); 130 for (final Iterator<TypeParameter> i = args.iterator(); i.hasNext(); ) { 131 final TypeParameter t = i.next(); 132 t.accept(this, arg); 133 if (i.hasNext()) { 134 printer.print(", "); 135 } 136 } 137 printer.print(">"); 138 } 139 } 140 printArguments(final NodeList<Expression> args, final Void arg)141 private void printArguments(final NodeList<Expression> args, final Void arg) { 142 printer.print("("); 143 if (!isNullOrEmpty(args)) { 144 boolean columnAlignParameters = (args.size() > 1) && configuration.isColumnAlignParameters(); 145 if (columnAlignParameters) { 146 printer.indentWithAlignTo(printer.getCursor().column); 147 } 148 for (final Iterator<Expression> i = args.iterator(); i.hasNext(); ) { 149 final Expression e = i.next(); 150 e.accept(this, arg); 151 if (i.hasNext()) { 152 printer.print(","); 153 if (columnAlignParameters) { 154 printer.println(); 155 } else { 156 printer.print(" "); 157 } 158 } 159 } 160 if (columnAlignParameters) { 161 printer.unindent(); 162 } 163 } 164 printer.print(")"); 165 } 166 printPrePostFixOptionalList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix)167 private void printPrePostFixOptionalList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix) { 168 if (!args.isEmpty()) { 169 printer.print(prefix); 170 for (final Iterator<? extends Visitable> i = args.iterator(); i.hasNext(); ) { 171 final Visitable v = i.next(); 172 v.accept(this, arg); 173 if (i.hasNext()) { 174 printer.print(separator); 175 } 176 } 177 printer.print(postfix); 178 } 179 } 180 printPrePostFixRequiredList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix)181 private void printPrePostFixRequiredList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix) { 182 printer.print(prefix); 183 if (!args.isEmpty()) { 184 for (final Iterator<? extends Visitable> i = args.iterator(); i.hasNext(); ) { 185 final Visitable v = i.next(); 186 v.accept(this, arg); 187 if (i.hasNext()) { 188 printer.print(separator); 189 } 190 } 191 } 192 printer.print(postfix); 193 } 194 printComment(final Optional<Comment> comment, final Void arg)195 private void printComment(final Optional<Comment> comment, final Void arg) { 196 comment.ifPresent(c -> c.accept(this, arg)); 197 } 198 199 @Override visit(final CompilationUnit n, final Void arg)200 public void visit(final CompilationUnit n, final Void arg) { 201 printComment(n.getComment(), arg); 202 if (n.getParsed() == UNPARSABLE) { 203 printer.println("???"); 204 return; 205 } 206 207 if (n.getPackageDeclaration().isPresent()) { 208 n.getPackageDeclaration().get().accept(this, arg); 209 } 210 211 n.getImports().accept(this, arg); 212 if (!n.getImports().isEmpty()) { 213 printer.println(); 214 } 215 216 for (final Iterator<TypeDeclaration<?>> i = n.getTypes().iterator(); i.hasNext(); ) { 217 i.next().accept(this, arg); 218 printer.println(); 219 if (i.hasNext()) { 220 printer.println(); 221 } 222 } 223 224 n.getModule().ifPresent(m -> m.accept(this, arg)); 225 226 printOrphanCommentsEnding(n); 227 } 228 229 @Override visit(final PackageDeclaration n, final Void arg)230 public void visit(final PackageDeclaration n, final Void arg) { 231 printComment(n.getComment(), arg); 232 printMemberAnnotations(n.getAnnotations(), arg); 233 printer.print("package "); 234 n.getName().accept(this, arg); 235 printer.println(";"); 236 printer.println(); 237 238 printOrphanCommentsEnding(n); 239 } 240 241 @Override visit(final NameExpr n, final Void arg)242 public void visit(final NameExpr n, final Void arg) { 243 printComment(n.getComment(), arg); 244 n.getName().accept(this, arg); 245 246 printOrphanCommentsEnding(n); 247 } 248 249 @Override visit(final Name n, final Void arg)250 public void visit(final Name n, final Void arg) { 251 printComment(n.getComment(), arg); 252 if (n.getQualifier().isPresent()) { 253 n.getQualifier().get().accept(this, arg); 254 printer.print("."); 255 } 256 printer.print(n.getIdentifier()); 257 258 printOrphanCommentsEnding(n); 259 } 260 261 @Override visit(SimpleName n, Void arg)262 public void visit(SimpleName n, Void arg) { 263 printer.print(n.getIdentifier()); 264 } 265 266 @Override visit(final ClassOrInterfaceDeclaration n, final Void arg)267 public void visit(final ClassOrInterfaceDeclaration n, final Void arg) { 268 printComment(n.getComment(), arg); 269 printMemberAnnotations(n.getAnnotations(), arg); 270 printModifiers(n.getModifiers()); 271 272 if (n.isInterface()) { 273 printer.print("interface "); 274 } else { 275 printer.print("class "); 276 } 277 278 n.getName().accept(this, arg); 279 280 printTypeParameters(n.getTypeParameters(), arg); 281 282 if (!n.getExtendedTypes().isEmpty()) { 283 printer.print(" extends "); 284 for (final Iterator<ClassOrInterfaceType> i = n.getExtendedTypes().iterator(); i.hasNext(); ) { 285 final ClassOrInterfaceType c = i.next(); 286 c.accept(this, arg); 287 if (i.hasNext()) { 288 printer.print(", "); 289 } 290 } 291 } 292 293 if (!n.getImplementedTypes().isEmpty()) { 294 printer.print(" implements "); 295 for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) { 296 final ClassOrInterfaceType c = i.next(); 297 c.accept(this, arg); 298 if (i.hasNext()) { 299 printer.print(", "); 300 } 301 } 302 } 303 304 printer.println(" {"); 305 printer.indent(); 306 if (!isNullOrEmpty(n.getMembers())) { 307 printMembers(n.getMembers(), arg); 308 } 309 310 printOrphanCommentsEnding(n); 311 312 printer.unindent(); 313 printer.print("}"); 314 } 315 316 @Override visit(final JavadocComment n, final Void arg)317 public void visit(final JavadocComment n, final Void arg) { 318 if (configuration.isPrintComments() && configuration.isPrintJavadoc()) { 319 printer.println("/**"); 320 final String commentContent = normalizeEolInTextBlock(n.getContent(), configuration.getEndOfLineCharacter()); 321 String[] lines = commentContent.split("\\R"); 322 List<String> strippedLines = new ArrayList<>(); 323 for (String line : lines) { 324 final String trimmedLine = line.trim(); 325 if (trimmedLine.startsWith("*")) { 326 line = trimmedLine.substring(1); 327 } 328 line = trimTrailingSpaces(line); 329 strippedLines.add(line); 330 } 331 332 boolean skippingLeadingEmptyLines = true; 333 boolean prependEmptyLine = false; 334 boolean prependSpace = strippedLines.stream().anyMatch(line -> !line.isEmpty() && !line.startsWith(" ")); 335 for (String line : strippedLines) { 336 if (line.isEmpty()) { 337 if (!skippingLeadingEmptyLines) { 338 prependEmptyLine = true; 339 } 340 } else { 341 skippingLeadingEmptyLines = false; 342 if (prependEmptyLine) { 343 printer.println(" *"); 344 prependEmptyLine = false; 345 } 346 printer.print(" *"); 347 if (prependSpace) { 348 printer.print(" "); 349 } 350 printer.println(line); 351 } 352 } 353 printer.println(" */"); 354 } 355 } 356 357 @Override visit(final ClassOrInterfaceType n, final Void arg)358 public void visit(final ClassOrInterfaceType n, final Void arg) { 359 printComment(n.getComment(), arg); 360 if (n.getScope().isPresent()) { 361 n.getScope().get().accept(this, arg); 362 printer.print("."); 363 } 364 printAnnotations(n.getAnnotations(), false, arg); 365 366 n.getName().accept(this, arg); 367 368 if (n.isUsingDiamondOperator()) { 369 printer.print("<>"); 370 } else { 371 printTypeArgs(n, arg); 372 } 373 } 374 375 @Override visit(final TypeParameter n, final Void arg)376 public void visit(final TypeParameter n, final Void arg) { 377 printComment(n.getComment(), arg); 378 printAnnotations(n.getAnnotations(), false, arg); 379 n.getName().accept(this, arg); 380 if (!isNullOrEmpty(n.getTypeBound())) { 381 printer.print(" extends "); 382 for (final Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext(); ) { 383 final ClassOrInterfaceType c = i.next(); 384 c.accept(this, arg); 385 if (i.hasNext()) { 386 printer.print(" & "); 387 } 388 } 389 } 390 } 391 392 @Override visit(final PrimitiveType n, final Void arg)393 public void visit(final PrimitiveType n, final Void arg) { 394 printComment(n.getComment(), arg); 395 printAnnotations(n.getAnnotations(), true, arg); 396 printer.print(n.getType().asString()); 397 } 398 399 @Override visit(final ArrayType n, final Void arg)400 public void visit(final ArrayType n, final Void arg) { 401 final List<ArrayType> arrayTypeBuffer = new LinkedList<>(); 402 Type type = n; 403 while (type instanceof ArrayType) { 404 final ArrayType arrayType = (ArrayType) type; 405 arrayTypeBuffer.add(arrayType); 406 type = arrayType.getComponentType(); 407 } 408 409 type.accept(this, arg); 410 for (ArrayType arrayType : arrayTypeBuffer) { 411 printAnnotations(arrayType.getAnnotations(), true, arg); 412 printer.print("[]"); 413 } 414 } 415 416 @Override visit(final ArrayCreationLevel n, final Void arg)417 public void visit(final ArrayCreationLevel n, final Void arg) { 418 printAnnotations(n.getAnnotations(), true, arg); 419 printer.print("["); 420 if (n.getDimension().isPresent()) { 421 n.getDimension().get().accept(this, arg); 422 } 423 printer.print("]"); 424 } 425 426 @Override visit(final IntersectionType n, final Void arg)427 public void visit(final IntersectionType n, final Void arg) { 428 printComment(n.getComment(), arg); 429 printAnnotations(n.getAnnotations(), false, arg); 430 boolean isFirst = true; 431 for (ReferenceType element : n.getElements()) { 432 if (isFirst) { 433 isFirst = false; 434 } else { 435 printer.print(" & "); 436 } 437 element.accept(this, arg); 438 } 439 } 440 441 @Override visit(final UnionType n, final Void arg)442 public void visit(final UnionType n, final Void arg) { 443 printComment(n.getComment(), arg); 444 printAnnotations(n.getAnnotations(), true, arg); 445 boolean isFirst = true; 446 for (ReferenceType element : n.getElements()) { 447 if (isFirst) { 448 isFirst = false; 449 } else { 450 printer.print(" | "); 451 } 452 element.accept(this, arg); 453 } 454 } 455 456 @Override visit(final WildcardType n, final Void arg)457 public void visit(final WildcardType n, final Void arg) { 458 printComment(n.getComment(), arg); 459 printAnnotations(n.getAnnotations(), false, arg); 460 printer.print("?"); 461 if (n.getExtendedType().isPresent()) { 462 printer.print(" extends "); 463 n.getExtendedType().get().accept(this, arg); 464 } 465 if (n.getSuperType().isPresent()) { 466 printer.print(" super "); 467 n.getSuperType().get().accept(this, arg); 468 } 469 } 470 471 @Override visit(final UnknownType n, final Void arg)472 public void visit(final UnknownType n, final Void arg) { 473 // Nothing to print 474 } 475 476 @Override visit(final FieldDeclaration n, final Void arg)477 public void visit(final FieldDeclaration n, final Void arg) { 478 printOrphanCommentsBeforeThisChildNode(n); 479 480 printComment(n.getComment(), arg); 481 printMemberAnnotations(n.getAnnotations(), arg); 482 printModifiers(n.getModifiers()); 483 if (!n.getVariables().isEmpty()) { 484 Optional<Type> maximumCommonType = n.getMaximumCommonType(); 485 maximumCommonType.ifPresent(t -> t.accept(this, arg)); 486 if (!maximumCommonType.isPresent()) { 487 printer.print("???"); 488 } 489 } 490 491 printer.print(" "); 492 for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) { 493 final VariableDeclarator var = i.next(); 494 var.accept(this, arg); 495 if (i.hasNext()) { 496 printer.print(", "); 497 } 498 } 499 500 printer.print(";"); 501 } 502 503 @Override visit(final VariableDeclarator n, final Void arg)504 public void visit(final VariableDeclarator n, final Void arg) { 505 printComment(n.getComment(), arg); 506 n.getName().accept(this, arg); 507 508 n.findAncestor(NodeWithVariables.class).ifPresent(ancestor -> ((NodeWithVariables<?>) ancestor).getMaximumCommonType().ifPresent(commonType -> { 509 510 final Type type = n.getType(); 511 512 ArrayType arrayType = null; 513 514 for (int i = commonType.getArrayLevel(); i < type.getArrayLevel(); i++) { 515 if (arrayType == null) { 516 arrayType = (ArrayType) type; 517 } else { 518 arrayType = (ArrayType) arrayType.getComponentType(); 519 } 520 printAnnotations(arrayType.getAnnotations(), true, arg); 521 printer.print("[]"); 522 } 523 })); 524 525 if (n.getInitializer().isPresent()) { 526 printer.print(" = "); 527 n.getInitializer().get().accept(this, arg); 528 } 529 } 530 531 @Override visit(final ArrayInitializerExpr n, final Void arg)532 public void visit(final ArrayInitializerExpr n, final Void arg) { 533 printComment(n.getComment(), arg); 534 printer.print("{"); 535 if (!isNullOrEmpty(n.getValues())) { 536 printer.print(" "); 537 for (final Iterator<Expression> i = n.getValues().iterator(); i.hasNext(); ) { 538 final Expression expr = i.next(); 539 expr.accept(this, arg); 540 if (i.hasNext()) { 541 printer.print(", "); 542 } 543 } 544 printer.print(" "); 545 } 546 printOrphanCommentsEnding(n); 547 printer.print("}"); 548 } 549 550 @Override visit(final VoidType n, final Void arg)551 public void visit(final VoidType n, final Void arg) { 552 printComment(n.getComment(), arg); 553 printAnnotations(n.getAnnotations(), false, arg); 554 printer.print("void"); 555 } 556 557 @Override visit(final VarType n, final Void arg)558 public void visit(final VarType n, final Void arg) { 559 printComment(n.getComment(), arg); 560 printAnnotations(n.getAnnotations(), false, arg); 561 printer.print("var"); 562 } 563 564 @Override visit(Modifier n, Void arg)565 public void visit(Modifier n, Void arg) { 566 printer.print(n.getKeyword().asString()); 567 printer.print(" "); 568 } 569 570 @Override visit(final ArrayAccessExpr n, final Void arg)571 public void visit(final ArrayAccessExpr n, final Void arg) { 572 printComment(n.getComment(), arg); 573 n.getName().accept(this, arg); 574 printer.print("["); 575 n.getIndex().accept(this, arg); 576 printer.print("]"); 577 } 578 579 @Override visit(final ArrayCreationExpr n, final Void arg)580 public void visit(final ArrayCreationExpr n, final Void arg) { 581 printComment(n.getComment(), arg); 582 printer.print("new "); 583 n.getElementType().accept(this, arg); 584 for (ArrayCreationLevel level : n.getLevels()) { 585 level.accept(this, arg); 586 } 587 if (n.getInitializer().isPresent()) { 588 printer.print(" "); 589 n.getInitializer().get().accept(this, arg); 590 } 591 } 592 593 @Override visit(final AssignExpr n, final Void arg)594 public void visit(final AssignExpr n, final Void arg) { 595 printComment(n.getComment(), arg); 596 n.getTarget().accept(this, arg); 597 printer.print(" "); 598 printer.print(n.getOperator().asString()); 599 printer.print(" "); 600 n.getValue().accept(this, arg); 601 } 602 603 @Override visit(final BinaryExpr n, final Void arg)604 public void visit(final BinaryExpr n, final Void arg) { 605 printComment(n.getComment(), arg); 606 n.getLeft().accept(this, arg); 607 printer.print(" "); 608 printer.print(n.getOperator().asString()); 609 printer.print(" "); 610 n.getRight().accept(this, arg); 611 } 612 613 @Override visit(final CastExpr n, final Void arg)614 public void visit(final CastExpr n, final Void arg) { 615 printComment(n.getComment(), arg); 616 printer.print("("); 617 n.getType().accept(this, arg); 618 printer.print(") "); 619 n.getExpression().accept(this, arg); 620 } 621 622 @Override visit(final ClassExpr n, final Void arg)623 public void visit(final ClassExpr n, final Void arg) { 624 printComment(n.getComment(), arg); 625 n.getType().accept(this, arg); 626 printer.print(".class"); 627 } 628 629 @Override visit(final ConditionalExpr n, final Void arg)630 public void visit(final ConditionalExpr n, final Void arg) { 631 printComment(n.getComment(), arg); 632 n.getCondition().accept(this, arg); 633 printer.print(" ? "); 634 n.getThenExpr().accept(this, arg); 635 printer.print(" : "); 636 n.getElseExpr().accept(this, arg); 637 } 638 639 @Override visit(final EnclosedExpr n, final Void arg)640 public void visit(final EnclosedExpr n, final Void arg) { 641 printComment(n.getComment(), arg); 642 printer.print("("); 643 n.getInner().accept(this, arg); 644 printer.print(")"); 645 } 646 647 @Override visit(final FieldAccessExpr n, final Void arg)648 public void visit(final FieldAccessExpr n, final Void arg) { 649 printComment(n.getComment(), arg); 650 n.getScope().accept(this, arg); 651 printer.print("."); 652 n.getName().accept(this, arg); 653 } 654 655 @Override visit(final InstanceOfExpr n, final Void arg)656 public void visit(final InstanceOfExpr n, final Void arg) { 657 printComment(n.getComment(), arg); 658 n.getExpression().accept(this, arg); 659 printer.print(" instanceof "); 660 n.getType().accept(this, arg); 661 } 662 663 @Override visit(final CharLiteralExpr n, final Void arg)664 public void visit(final CharLiteralExpr n, final Void arg) { 665 printComment(n.getComment(), arg); 666 printer.print("'"); 667 printer.print(n.getValue()); 668 printer.print("'"); 669 } 670 671 @Override visit(final DoubleLiteralExpr n, final Void arg)672 public void visit(final DoubleLiteralExpr n, final Void arg) { 673 printComment(n.getComment(), arg); 674 printer.print(n.getValue()); 675 } 676 677 @Override visit(final IntegerLiteralExpr n, final Void arg)678 public void visit(final IntegerLiteralExpr n, final Void arg) { 679 printComment(n.getComment(), arg); 680 printer.print(n.getValue()); 681 } 682 683 @Override visit(final LongLiteralExpr n, final Void arg)684 public void visit(final LongLiteralExpr n, final Void arg) { 685 printComment(n.getComment(), arg); 686 printer.print(n.getValue()); 687 } 688 689 @Override visit(final StringLiteralExpr n, final Void arg)690 public void visit(final StringLiteralExpr n, final Void arg) { 691 printComment(n.getComment(), arg); 692 printer.print("\""); 693 printer.print(n.getValue()); 694 printer.print("\""); 695 } 696 697 @Override visit(final BooleanLiteralExpr n, final Void arg)698 public void visit(final BooleanLiteralExpr n, final Void arg) { 699 printComment(n.getComment(), arg); 700 printer.print(String.valueOf(n.getValue())); 701 } 702 703 @Override visit(final NullLiteralExpr n, final Void arg)704 public void visit(final NullLiteralExpr n, final Void arg) { 705 printComment(n.getComment(), arg); 706 printer.print("null"); 707 } 708 709 @Override visit(final ThisExpr n, final Void arg)710 public void visit(final ThisExpr n, final Void arg) { 711 printComment(n.getComment(), arg); 712 if (n.getTypeName().isPresent()) { 713 n.getTypeName().get().accept(this, arg); 714 printer.print("."); 715 } 716 printer.print("this"); 717 } 718 719 @Override visit(final SuperExpr n, final Void arg)720 public void visit(final SuperExpr n, final Void arg) { 721 printComment(n.getComment(), arg); 722 if (n.getTypeName().isPresent()) { 723 n.getTypeName().get().accept(this, arg); 724 printer.print("."); 725 } 726 printer.print("super"); 727 } 728 729 @Override visit(final MethodCallExpr n, final Void arg)730 public void visit(final MethodCallExpr n, final Void arg) { 731 printComment(n.getComment(), arg); 732 733 // determine whether we do reindenting for aligmnent at all 734 // - is it enabled? 735 // - are we in a statement where we want the alignment? 736 // - are we not directly in the argument list of a method call expression? 737 AtomicBoolean columnAlignFirstMethodChain = new AtomicBoolean(); 738 if (configuration.isColumnAlignFirstMethodChain()) { 739 // pick the kind of expressions where vertically aligning method calls is okay. 740 if (n.findAncestor(Statement.class).map(p -> p.isReturnStmt() 741 || p.isThrowStmt() 742 || p.isAssertStmt() 743 || p.isExpressionStmt()).orElse(false)) { 744 // search for first parent that does not have its child as scope 745 Node c = n; 746 Optional<Node> p = c.getParentNode(); 747 while (p.isPresent() && p.filter(NodeWithTraversableScope.class::isInstance) 748 .map(NodeWithTraversableScope.class::cast) 749 .flatMap(NodeWithTraversableScope::traverseScope) 750 .map(c::equals) 751 .orElse(false)) { 752 c = p.get(); 753 p = c.getParentNode(); 754 } 755 756 // check if the parent is a method call and thus we are in an argument list 757 columnAlignFirstMethodChain.set(!p.filter(MethodCallExpr.class::isInstance).isPresent()); 758 } 759 } 760 761 // we are at the last method call of a call chain 762 // this means we do not start reindenting for alignment or we undo it 763 AtomicBoolean lastMethodInCallChain = new AtomicBoolean(true); 764 if (columnAlignFirstMethodChain.get()) { 765 Node node = n; 766 while (node.getParentNode() 767 .filter(NodeWithTraversableScope.class::isInstance) 768 .map(NodeWithTraversableScope.class::cast) 769 .flatMap(NodeWithTraversableScope::traverseScope) 770 .map(node::equals) 771 .orElse(false)) { 772 node = node.getParentNode().orElseThrow(AssertionError::new); 773 if (node instanceof MethodCallExpr) { 774 lastMethodInCallChain.set(false); 775 break; 776 } 777 } 778 } 779 780 // search whether there is a method call with scope in the scope already 781 // this means that we probably started reindenting for alignment there 782 AtomicBoolean methodCallWithScopeInScope = new AtomicBoolean(); 783 if (columnAlignFirstMethodChain.get()) { 784 Optional<Expression> s = n.getScope(); 785 while (s.filter(NodeWithTraversableScope.class::isInstance).isPresent()) { 786 Optional<Expression> parentScope = s.map(NodeWithTraversableScope.class::cast) 787 .flatMap(NodeWithTraversableScope::traverseScope); 788 if (s.filter(MethodCallExpr.class::isInstance).isPresent() && parentScope.isPresent()) { 789 methodCallWithScopeInScope.set(true); 790 break; 791 } 792 s = parentScope; 793 } 794 } 795 796 // we have a scope 797 // this means we are not the first method in the chain 798 n.getScope().ifPresent(scope -> { 799 scope.accept(this, arg); 800 if (columnAlignFirstMethodChain.get()) { 801 if (methodCallWithScopeInScope.get()) { 802 /* We're a method call on the result of something (method call, property access, ...) that is not stand alone, 803 and not the first one with scope, like: 804 we're x() in a.b().x(), or in a=b().c[15].d.e().x(). 805 That means that the "else" has been executed by one of the methods in the scope chain, so that the alignment 806 is set to the "." of that method. 807 That means we will align to that "." when we start a new line: */ 808 printer.println(); 809 } else if (!lastMethodInCallChain.get()) { 810 /* We're the first method call on the result of something in the chain (method call, property access, ...), 811 but we are not at the same time the last method call in that chain, like: 812 we're x() in a().x().y(), or in Long.x().y.z(). That means we get to dictate the indent of following method 813 calls in this chain by setting the cursor to where we are now: just before the "." 814 that start this method call. */ 815 printer.reindentWithAlignToCursor(); 816 } 817 } 818 printer.print("."); 819 }); 820 821 printTypeArgs(n, arg); 822 n.getName().accept(this, arg); 823 printer.duplicateIndent(); 824 printArguments(n.getArguments(), arg); 825 printer.unindent(); 826 if (columnAlignFirstMethodChain.get() && methodCallWithScopeInScope.get() && lastMethodInCallChain.get()) { 827 // undo the aligning after the arguments of the last method call are printed 828 printer.reindentToPreviousLevel(); 829 } 830 } 831 832 @Override visit(final ObjectCreationExpr n, final Void arg)833 public void visit(final ObjectCreationExpr n, final Void arg) { 834 printComment(n.getComment(), arg); 835 if (n.getScope().isPresent()) { 836 n.getScope().get().accept(this, arg); 837 printer.print("."); 838 } 839 840 printer.print("new "); 841 842 printTypeArgs(n, arg); 843 if (!isNullOrEmpty(n.getTypeArguments().orElse(null))) { 844 printer.print(" "); 845 } 846 847 n.getType().accept(this, arg); 848 849 printArguments(n.getArguments(), arg); 850 851 if (n.getAnonymousClassBody().isPresent()) { 852 printer.println(" {"); 853 printer.indent(); 854 printMembers(n.getAnonymousClassBody().get(), arg); 855 printer.unindent(); 856 printer.print("}"); 857 } 858 } 859 860 @Override visit(final UnaryExpr n, final Void arg)861 public void visit(final UnaryExpr n, final Void arg) { 862 printComment(n.getComment(), arg); 863 if (n.getOperator().isPrefix()) { 864 printer.print(n.getOperator().asString()); 865 } 866 867 n.getExpression().accept(this, arg); 868 869 if (n.getOperator().isPostfix()) { 870 printer.print(n.getOperator().asString()); 871 } 872 } 873 874 @Override visit(final ConstructorDeclaration n, final Void arg)875 public void visit(final ConstructorDeclaration n, final Void arg) { 876 printComment(n.getComment(), arg); 877 printMemberAnnotations(n.getAnnotations(), arg); 878 printModifiers(n.getModifiers()); 879 880 printTypeParameters(n.getTypeParameters(), arg); 881 if (n.isGeneric()) { 882 printer.print(" "); 883 } 884 n.getName().accept(this, arg); 885 886 printer.print("("); 887 if (!n.getParameters().isEmpty()) { 888 for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) { 889 final Parameter p = i.next(); 890 p.accept(this, arg); 891 if (i.hasNext()) { 892 printer.print(", "); 893 } 894 } 895 } 896 printer.print(")"); 897 898 if (!isNullOrEmpty(n.getThrownExceptions())) { 899 printer.print(" throws "); 900 for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) { 901 final ReferenceType name = i.next(); 902 name.accept(this, arg); 903 if (i.hasNext()) { 904 printer.print(", "); 905 } 906 } 907 } 908 printer.print(" "); 909 n.getBody().accept(this, arg); 910 } 911 912 @Override visit(final MethodDeclaration n, final Void arg)913 public void visit(final MethodDeclaration n, final Void arg) { 914 printOrphanCommentsBeforeThisChildNode(n); 915 916 printComment(n.getComment(), arg); 917 printMemberAnnotations(n.getAnnotations(), arg); 918 printModifiers(n.getModifiers()); 919 printTypeParameters(n.getTypeParameters(), arg); 920 if (!isNullOrEmpty(n.getTypeParameters())) { 921 printer.print(" "); 922 } 923 924 n.getType().accept(this, arg); 925 printer.print(" "); 926 n.getName().accept(this, arg); 927 928 printer.print("("); 929 n.getReceiverParameter().ifPresent(rp -> { 930 rp.accept(this, arg); 931 if (!isNullOrEmpty(n.getParameters())) { 932 printer.print(", "); 933 } 934 }); 935 if (!isNullOrEmpty(n.getParameters())) { 936 for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) { 937 final Parameter p = i.next(); 938 p.accept(this, arg); 939 if (i.hasNext()) { 940 printer.print(", "); 941 } 942 } 943 } 944 printer.print(")"); 945 946 if (!isNullOrEmpty(n.getThrownExceptions())) { 947 printer.print(" throws "); 948 for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) { 949 final ReferenceType name = i.next(); 950 name.accept(this, arg); 951 if (i.hasNext()) { 952 printer.print(", "); 953 } 954 } 955 } 956 if (!n.getBody().isPresent()) { 957 printer.print(";"); 958 } else { 959 printer.print(" "); 960 n.getBody().get().accept(this, arg); 961 } 962 } 963 964 @Override visit(final Parameter n, final Void arg)965 public void visit(final Parameter n, final Void arg) { 966 printComment(n.getComment(), arg); 967 printAnnotations(n.getAnnotations(), false, arg); 968 printModifiers(n.getModifiers()); 969 n.getType().accept(this, arg); 970 if (n.isVarArgs()) { 971 printAnnotations(n.getVarArgsAnnotations(), false, arg); 972 printer.print("..."); 973 } 974 if (!(n.getType() instanceof UnknownType)) { 975 printer.print(" "); 976 } 977 n.getName().accept(this, arg); 978 } 979 980 @Override visit(final ReceiverParameter n, final Void arg)981 public void visit(final ReceiverParameter n, final Void arg) { 982 printComment(n.getComment(), arg); 983 printAnnotations(n.getAnnotations(), false, arg); 984 n.getType().accept(this, arg); 985 printer.print(" "); 986 n.getName().accept(this, arg); 987 } 988 989 @Override visit(final ExplicitConstructorInvocationStmt n, final Void arg)990 public void visit(final ExplicitConstructorInvocationStmt n, final Void arg) { 991 printComment(n.getComment(), arg); 992 if (n.isThis()) { 993 printTypeArgs(n, arg); 994 printer.print("this"); 995 } else { 996 if (n.getExpression().isPresent()) { 997 n.getExpression().get().accept(this, arg); 998 printer.print("."); 999 } 1000 printTypeArgs(n, arg); 1001 printer.print("super"); 1002 } 1003 printArguments(n.getArguments(), arg); 1004 printer.print(";"); 1005 } 1006 1007 @Override visit(final VariableDeclarationExpr n, final Void arg)1008 public void visit(final VariableDeclarationExpr n, final Void arg) { 1009 printComment(n.getComment(), arg); 1010 if (n.getParentNode().map(ExpressionStmt.class::isInstance).orElse(false)) { 1011 printMemberAnnotations(n.getAnnotations(), arg); 1012 } else { 1013 printAnnotations(n.getAnnotations(), false, arg); 1014 } 1015 printModifiers(n.getModifiers()); 1016 1017 if (!n.getVariables().isEmpty()) { 1018 n.getMaximumCommonType().ifPresent(t -> t.accept(this, arg)); 1019 } 1020 printer.print(" "); 1021 1022 for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) { 1023 final VariableDeclarator v = i.next(); 1024 v.accept(this, arg); 1025 if (i.hasNext()) { 1026 printer.print(", "); 1027 } 1028 } 1029 } 1030 1031 @Override visit(final LocalClassDeclarationStmt n, final Void arg)1032 public void visit(final LocalClassDeclarationStmt n, final Void arg) { 1033 printComment(n.getComment(), arg); 1034 n.getClassDeclaration().accept(this, arg); 1035 } 1036 1037 @Override visit(final AssertStmt n, final Void arg)1038 public void visit(final AssertStmt n, final Void arg) { 1039 printComment(n.getComment(), arg); 1040 printer.print("assert "); 1041 n.getCheck().accept(this, arg); 1042 if (n.getMessage().isPresent()) { 1043 printer.print(" : "); 1044 n.getMessage().get().accept(this, arg); 1045 } 1046 printer.print(";"); 1047 } 1048 1049 @Override visit(final BlockStmt n, final Void arg)1050 public void visit(final BlockStmt n, final Void arg) { 1051 printOrphanCommentsBeforeThisChildNode(n); 1052 printComment(n.getComment(), arg); 1053 printer.println("{"); 1054 if (n.getStatements() != null) { 1055 printer.indent(); 1056 for (final Statement s : n.getStatements()) { 1057 s.accept(this, arg); 1058 printer.println(); 1059 } 1060 printer.unindent(); 1061 } 1062 printOrphanCommentsEnding(n); 1063 printer.print("}"); 1064 } 1065 1066 @Override visit(final LabeledStmt n, final Void arg)1067 public void visit(final LabeledStmt n, final Void arg) { 1068 printComment(n.getComment(), arg); 1069 n.getLabel().accept(this, arg); 1070 printer.print(": "); 1071 n.getStatement().accept(this, arg); 1072 } 1073 1074 @Override visit(final EmptyStmt n, final Void arg)1075 public void visit(final EmptyStmt n, final Void arg) { 1076 printComment(n.getComment(), arg); 1077 printer.print(";"); 1078 } 1079 1080 @Override visit(final ExpressionStmt n, final Void arg)1081 public void visit(final ExpressionStmt n, final Void arg) { 1082 printOrphanCommentsBeforeThisChildNode(n); 1083 printComment(n.getComment(), arg); 1084 n.getExpression().accept(this, arg); 1085 printer.print(";"); 1086 } 1087 1088 @Override visit(final SwitchStmt n, final Void arg)1089 public void visit(final SwitchStmt n, final Void arg) { 1090 printSwitchNode(n, arg); 1091 } 1092 1093 @Override visit(SwitchExpr n, Void arg)1094 public void visit(SwitchExpr n, Void arg) { 1095 printSwitchNode(n, arg); 1096 } 1097 printSwitchNode(SwitchNode n, Void arg)1098 private void printSwitchNode(SwitchNode n, Void arg) { 1099 printComment(n.getComment(), arg); 1100 printer.print("switch("); 1101 n.getSelector().accept(this, arg); 1102 printer.println(") {"); 1103 if (n.getEntries() != null) { 1104 printer.indent(); 1105 for (final SwitchEntry e : n.getEntries()) { 1106 e.accept(this, arg); 1107 } 1108 printer.unindent(); 1109 } 1110 printer.print("}"); 1111 } 1112 1113 @Override visit(final SwitchEntry n, final Void arg)1114 public void visit(final SwitchEntry n, final Void arg) { 1115 printComment(n.getComment(), arg); 1116 1117 if (isNullOrEmpty(n.getLabels())) { 1118 printer.print("default:"); 1119 } else { 1120 printer.print("case "); 1121 for (final Iterator<Expression> i = n.getLabels().iterator(); i.hasNext(); ) { 1122 final Expression label = i.next(); 1123 label.accept(this, arg); 1124 if (i.hasNext()) { 1125 printer.print(", "); 1126 } 1127 } 1128 printer.print(":"); 1129 } 1130 printer.println(); 1131 printer.indent(); 1132 if (n.getStatements() != null) { 1133 for (final Statement s : n.getStatements()) { 1134 s.accept(this, arg); 1135 printer.println(); 1136 } 1137 } 1138 printer.unindent(); 1139 } 1140 1141 @Override visit(final BreakStmt n, final Void arg)1142 public void visit(final BreakStmt n, final Void arg) { 1143 printComment(n.getComment(), arg); 1144 printer.print("break"); 1145 n.getValue().ifPresent(value -> { 1146 printer.print(" "); 1147 value.accept(this, arg); 1148 }); 1149 printer.print(";"); 1150 } 1151 1152 @Override visit(final ReturnStmt n, final Void arg)1153 public void visit(final ReturnStmt n, final Void arg) { 1154 printComment(n.getComment(), arg); 1155 printer.print("return"); 1156 if (n.getExpression().isPresent()) { 1157 printer.print(" "); 1158 n.getExpression().get().accept(this, arg); 1159 } 1160 printer.print(";"); 1161 } 1162 1163 @Override visit(final EnumDeclaration n, final Void arg)1164 public void visit(final EnumDeclaration n, final Void arg) { 1165 printComment(n.getComment(), arg); 1166 printMemberAnnotations(n.getAnnotations(), arg); 1167 printModifiers(n.getModifiers()); 1168 1169 printer.print("enum "); 1170 n.getName().accept(this, arg); 1171 1172 if (!n.getImplementedTypes().isEmpty()) { 1173 printer.print(" implements "); 1174 for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) { 1175 final ClassOrInterfaceType c = i.next(); 1176 c.accept(this, arg); 1177 if (i.hasNext()) { 1178 printer.print(", "); 1179 } 1180 } 1181 } 1182 1183 printer.println(" {"); 1184 printer.indent(); 1185 if (n.getEntries().isNonEmpty()) { 1186 final boolean alignVertically = 1187 // Either we hit the constant amount limit in the configurations, or... 1188 n.getEntries().size() > configuration.getMaxEnumConstantsToAlignHorizontally() || 1189 // any of the constants has a comment. 1190 n.getEntries().stream().anyMatch(e -> e.getComment().isPresent()); 1191 printer.println(); 1192 for (final Iterator<EnumConstantDeclaration> i = n.getEntries().iterator(); i.hasNext(); ) { 1193 final EnumConstantDeclaration e = i.next(); 1194 e.accept(this, arg); 1195 if (i.hasNext()) { 1196 if (alignVertically) { 1197 printer.println(","); 1198 } else { 1199 printer.print(", "); 1200 } 1201 } 1202 } 1203 } 1204 if (!n.getMembers().isEmpty()) { 1205 printer.println(";"); 1206 printMembers(n.getMembers(), arg); 1207 } else { 1208 if (!n.getEntries().isEmpty()) { 1209 printer.println(); 1210 } 1211 } 1212 printer.unindent(); 1213 printer.print("}"); 1214 } 1215 1216 @Override visit(final EnumConstantDeclaration n, final Void arg)1217 public void visit(final EnumConstantDeclaration n, final Void arg) { 1218 printComment(n.getComment(), arg); 1219 printMemberAnnotations(n.getAnnotations(), arg); 1220 n.getName().accept(this, arg); 1221 1222 if (!n.getArguments().isEmpty()) { 1223 printArguments(n.getArguments(), arg); 1224 } 1225 1226 if (!n.getClassBody().isEmpty()) { 1227 printer.println(" {"); 1228 printer.indent(); 1229 printMembers(n.getClassBody(), arg); 1230 printer.unindent(); 1231 printer.println("}"); 1232 } 1233 } 1234 1235 @Override visit(final InitializerDeclaration n, final Void arg)1236 public void visit(final InitializerDeclaration n, final Void arg) { 1237 printComment(n.getComment(), arg); 1238 if (n.isStatic()) { 1239 printer.print("static "); 1240 } 1241 n.getBody().accept(this, arg); 1242 } 1243 1244 @Override visit(final IfStmt n, final Void arg)1245 public void visit(final IfStmt n, final Void arg) { 1246 printComment(n.getComment(), arg); 1247 printer.print("if ("); 1248 n.getCondition().accept(this, arg); 1249 final boolean thenBlock = n.getThenStmt() instanceof BlockStmt; 1250 if (thenBlock) // block statement should start on the same line 1251 printer.print(") "); 1252 else { 1253 printer.println(")"); 1254 printer.indent(); 1255 } 1256 n.getThenStmt().accept(this, arg); 1257 if (!thenBlock) 1258 printer.unindent(); 1259 if (n.getElseStmt().isPresent()) { 1260 if (thenBlock) 1261 printer.print(" "); 1262 else 1263 printer.println(); 1264 final boolean elseIf = n.getElseStmt().orElse(null) instanceof IfStmt; 1265 final boolean elseBlock = n.getElseStmt().orElse(null) instanceof BlockStmt; 1266 if (elseIf || elseBlock) // put chained if and start of block statement on a same level 1267 printer.print("else "); 1268 else { 1269 printer.println("else"); 1270 printer.indent(); 1271 } 1272 if (n.getElseStmt().isPresent()) 1273 n.getElseStmt().get().accept(this, arg); 1274 if (!(elseIf || elseBlock)) 1275 printer.unindent(); 1276 } 1277 } 1278 1279 @Override visit(final WhileStmt n, final Void arg)1280 public void visit(final WhileStmt n, final Void arg) { 1281 printComment(n.getComment(), arg); 1282 printer.print("while ("); 1283 n.getCondition().accept(this, arg); 1284 printer.print(") "); 1285 n.getBody().accept(this, arg); 1286 } 1287 1288 @Override visit(final ContinueStmt n, final Void arg)1289 public void visit(final ContinueStmt n, final Void arg) { 1290 printComment(n.getComment(), arg); 1291 printer.print("continue"); 1292 n.getLabel().ifPresent(l -> printer.print(" ").print(l.getIdentifier())); 1293 printer.print(";"); 1294 } 1295 1296 @Override visit(final DoStmt n, final Void arg)1297 public void visit(final DoStmt n, final Void arg) { 1298 printComment(n.getComment(), arg); 1299 printer.print("do "); 1300 n.getBody().accept(this, arg); 1301 printer.print(" while ("); 1302 n.getCondition().accept(this, arg); 1303 printer.print(");"); 1304 } 1305 1306 @Override visit(final ForEachStmt n, final Void arg)1307 public void visit(final ForEachStmt n, final Void arg) { 1308 printComment(n.getComment(), arg); 1309 printer.print("for ("); 1310 n.getVariable().accept(this, arg); 1311 printer.print(" : "); 1312 n.getIterable().accept(this, arg); 1313 printer.print(") "); 1314 n.getBody().accept(this, arg); 1315 } 1316 1317 @Override visit(final ForStmt n, final Void arg)1318 public void visit(final ForStmt n, final Void arg) { 1319 printComment(n.getComment(), arg); 1320 printer.print("for ("); 1321 if (n.getInitialization() != null) { 1322 for (final Iterator<Expression> i = n.getInitialization().iterator(); i.hasNext(); ) { 1323 final Expression e = i.next(); 1324 e.accept(this, arg); 1325 if (i.hasNext()) { 1326 printer.print(", "); 1327 } 1328 } 1329 } 1330 printer.print("; "); 1331 if (n.getCompare().isPresent()) { 1332 n.getCompare().get().accept(this, arg); 1333 } 1334 printer.print("; "); 1335 if (n.getUpdate() != null) { 1336 for (final Iterator<Expression> i = n.getUpdate().iterator(); i.hasNext(); ) { 1337 final Expression e = i.next(); 1338 e.accept(this, arg); 1339 if (i.hasNext()) { 1340 printer.print(", "); 1341 } 1342 } 1343 } 1344 printer.print(") "); 1345 n.getBody().accept(this, arg); 1346 } 1347 1348 @Override visit(final ThrowStmt n, final Void arg)1349 public void visit(final ThrowStmt n, final Void arg) { 1350 printComment(n.getComment(), arg); 1351 printer.print("throw "); 1352 n.getExpression().accept(this, arg); 1353 printer.print(";"); 1354 } 1355 1356 @Override visit(final SynchronizedStmt n, final Void arg)1357 public void visit(final SynchronizedStmt n, final Void arg) { 1358 printComment(n.getComment(), arg); 1359 printer.print("synchronized ("); 1360 n.getExpression().accept(this, arg); 1361 printer.print(") "); 1362 n.getBody().accept(this, arg); 1363 } 1364 1365 @Override visit(final TryStmt n, final Void arg)1366 public void visit(final TryStmt n, final Void arg) { 1367 printComment(n.getComment(), arg); 1368 printer.print("try "); 1369 if (!n.getResources().isEmpty()) { 1370 printer.print("("); 1371 Iterator<Expression> resources = n.getResources().iterator(); 1372 boolean first = true; 1373 while (resources.hasNext()) { 1374 resources.next().accept(this, arg); 1375 if (resources.hasNext()) { 1376 printer.print(";"); 1377 printer.println(); 1378 if (first) { 1379 printer.indent(); 1380 } 1381 } 1382 first = false; 1383 } 1384 if (n.getResources().size() > 1) { 1385 printer.unindent(); 1386 } 1387 printer.print(") "); 1388 } 1389 n.getTryBlock().accept(this, arg); 1390 for (final CatchClause c : n.getCatchClauses()) { 1391 c.accept(this, arg); 1392 } 1393 if (n.getFinallyBlock().isPresent()) { 1394 printer.print(" finally "); 1395 n.getFinallyBlock().get().accept(this, arg); 1396 } 1397 } 1398 1399 @Override visit(final CatchClause n, final Void arg)1400 public void visit(final CatchClause n, final Void arg) { 1401 printComment(n.getComment(), arg); 1402 printer.print(" catch ("); 1403 n.getParameter().accept(this, arg); 1404 printer.print(") "); 1405 n.getBody().accept(this, arg); 1406 } 1407 1408 @Override visit(final AnnotationDeclaration n, final Void arg)1409 public void visit(final AnnotationDeclaration n, final Void arg) { 1410 printComment(n.getComment(), arg); 1411 printMemberAnnotations(n.getAnnotations(), arg); 1412 printModifiers(n.getModifiers()); 1413 1414 printer.print("@interface "); 1415 n.getName().accept(this, arg); 1416 printer.println(" {"); 1417 printer.indent(); 1418 if (n.getMembers() != null) { 1419 printMembers(n.getMembers(), arg); 1420 } 1421 printer.unindent(); 1422 printer.print("}"); 1423 } 1424 1425 @Override visit(final AnnotationMemberDeclaration n, final Void arg)1426 public void visit(final AnnotationMemberDeclaration n, final Void arg) { 1427 printComment(n.getComment(), arg); 1428 printMemberAnnotations(n.getAnnotations(), arg); 1429 printModifiers(n.getModifiers()); 1430 1431 n.getType().accept(this, arg); 1432 printer.print(" "); 1433 n.getName().accept(this, arg); 1434 printer.print("()"); 1435 if (n.getDefaultValue().isPresent()) { 1436 printer.print(" default "); 1437 n.getDefaultValue().get().accept(this, arg); 1438 } 1439 printer.print(";"); 1440 } 1441 1442 @Override visit(final MarkerAnnotationExpr n, final Void arg)1443 public void visit(final MarkerAnnotationExpr n, final Void arg) { 1444 printComment(n.getComment(), arg); 1445 printer.print("@"); 1446 n.getName().accept(this, arg); 1447 } 1448 1449 @Override visit(final SingleMemberAnnotationExpr n, final Void arg)1450 public void visit(final SingleMemberAnnotationExpr n, final Void arg) { 1451 printComment(n.getComment(), arg); 1452 printer.print("@"); 1453 n.getName().accept(this, arg); 1454 printer.print("("); 1455 n.getMemberValue().accept(this, arg); 1456 printer.print(")"); 1457 } 1458 1459 @Override visit(final NormalAnnotationExpr n, final Void arg)1460 public void visit(final NormalAnnotationExpr n, final Void arg) { 1461 printComment(n.getComment(), arg); 1462 printer.print("@"); 1463 n.getName().accept(this, arg); 1464 printer.print("("); 1465 if (n.getPairs() != null) { 1466 for (final Iterator<MemberValuePair> i = n.getPairs().iterator(); i.hasNext(); ) { 1467 final MemberValuePair m = i.next(); 1468 m.accept(this, arg); 1469 if (i.hasNext()) { 1470 printer.print(", "); 1471 } 1472 } 1473 } 1474 printer.print(")"); 1475 } 1476 1477 @Override visit(final MemberValuePair n, final Void arg)1478 public void visit(final MemberValuePair n, final Void arg) { 1479 printComment(n.getComment(), arg); 1480 n.getName().accept(this, arg); 1481 printer.print(" = "); 1482 n.getValue().accept(this, arg); 1483 } 1484 1485 @Override visit(final LineComment n, final Void arg)1486 public void visit(final LineComment n, final Void arg) { 1487 if (configuration.isIgnoreComments()) { 1488 return; 1489 } 1490 printer 1491 .print("// ") 1492 .println(normalizeEolInTextBlock(n.getContent(), "").trim()); 1493 } 1494 1495 @Override visit(final BlockComment n, final Void arg)1496 public void visit(final BlockComment n, final Void arg) { 1497 if (configuration.isIgnoreComments()) { 1498 return; 1499 } 1500 final String commentContent = normalizeEolInTextBlock(n.getContent(), configuration.getEndOfLineCharacter()); 1501 String[] lines = commentContent.split("\\R", -1); // as BlockComment should not be formatted, -1 to preserve any trailing empty line if present 1502 printer.print("/*"); 1503 for (int i = 0; i < (lines.length - 1); i++) { 1504 printer.print(lines[i]); 1505 printer.print(configuration.getEndOfLineCharacter()); // Avoids introducing indentation in blockcomments. ie: do not use println() as it would trigger indentation at the next print call. 1506 } 1507 printer.print(lines[lines.length - 1]); // last line is not followed by a newline, and simply terminated with `*/` 1508 printer.println("*/"); 1509 } 1510 1511 @Override visit(LambdaExpr n, Void arg)1512 public void visit(LambdaExpr n, Void arg) { 1513 printComment(n.getComment(), arg); 1514 1515 final NodeList<Parameter> parameters = n.getParameters(); 1516 final boolean printPar = n.isEnclosingParameters(); 1517 1518 if (printPar) { 1519 printer.print("("); 1520 } 1521 for (Iterator<Parameter> i = parameters.iterator(); i.hasNext(); ) { 1522 Parameter p = i.next(); 1523 p.accept(this, arg); 1524 if (i.hasNext()) { 1525 printer.print(", "); 1526 } 1527 } 1528 if (printPar) { 1529 printer.print(")"); 1530 } 1531 1532 printer.print(" -> "); 1533 final Statement body = n.getBody(); 1534 if (body instanceof ExpressionStmt) { 1535 // Print the expression directly 1536 ((ExpressionStmt) body).getExpression().accept(this, arg); 1537 } else { 1538 body.accept(this, arg); 1539 } 1540 } 1541 1542 @Override visit(MethodReferenceExpr n, Void arg)1543 public void visit(MethodReferenceExpr n, Void arg) { 1544 printComment(n.getComment(), arg); 1545 Expression scope = n.getScope(); 1546 String identifier = n.getIdentifier(); 1547 if (scope != null) { 1548 n.getScope().accept(this, arg); 1549 } 1550 1551 printer.print("::"); 1552 printTypeArgs(n, arg); 1553 if (identifier != null) { 1554 printer.print(identifier); 1555 } 1556 } 1557 1558 @Override visit(TypeExpr n, Void arg)1559 public void visit(TypeExpr n, Void arg) { 1560 printComment(n.getComment(), arg); 1561 if (n.getType() != null) { 1562 n.getType().accept(this, arg); 1563 } 1564 } 1565 1566 @Override visit(NodeList n, Void arg)1567 public void visit(NodeList n, Void arg) { 1568 if (configuration.isOrderImports() && n.size() > 0 && n.get(0) instanceof ImportDeclaration) { 1569 //noinspection unchecked 1570 NodeList<ImportDeclaration> modifiableList = new NodeList<>(n); 1571 modifiableList.sort( 1572 comparingInt((ImportDeclaration i) -> i.isStatic() ? 0 : 1) 1573 .thenComparing(NodeWithName::getNameAsString)); 1574 for (Object node : modifiableList) { 1575 ((Node) node).accept(this, arg); 1576 } 1577 } else { 1578 for (Object node : n) { 1579 ((Node) node).accept(this, arg); 1580 } 1581 } 1582 } 1583 1584 @Override visit(final ImportDeclaration n, final Void arg)1585 public void visit(final ImportDeclaration n, final Void arg) { 1586 printComment(n.getComment(), arg); 1587 printer.print("import "); 1588 if (n.isStatic()) { 1589 printer.print("static "); 1590 } 1591 n.getName().accept(this, arg); 1592 if (n.isAsterisk()) { 1593 printer.print(".*"); 1594 } 1595 printer.println(";"); 1596 1597 printOrphanCommentsEnding(n); 1598 } 1599 1600 1601 @Override visit(ModuleDeclaration n, Void arg)1602 public void visit(ModuleDeclaration n, Void arg) { 1603 printMemberAnnotations(n.getAnnotations(), arg); 1604 if (n.isOpen()) { 1605 printer.print("open "); 1606 } 1607 printer.print("module "); 1608 n.getName().accept(this, arg); 1609 printer.println(" {").indent(); 1610 n.getDirectives().accept(this, arg); 1611 printer.unindent().println("}"); 1612 } 1613 1614 @Override visit(ModuleRequiresDirective n, Void arg)1615 public void visit(ModuleRequiresDirective n, Void arg) { 1616 printer.print("requires "); 1617 printModifiers(n.getModifiers()); 1618 n.getName().accept(this, arg); 1619 printer.println(";"); 1620 } 1621 1622 @Override visit(ModuleExportsDirective n, Void arg)1623 public void visit(ModuleExportsDirective n, Void arg) { 1624 printer.print("exports "); 1625 n.getName().accept(this, arg); 1626 printPrePostFixOptionalList(n.getModuleNames(), arg, " to ", ", ", ""); 1627 printer.println(";"); 1628 } 1629 1630 @Override visit(ModuleProvidesDirective n, Void arg)1631 public void visit(ModuleProvidesDirective n, Void arg) { 1632 printer.print("provides "); 1633 n.getName().accept(this, arg); 1634 printPrePostFixRequiredList(n.getWith(), arg, " with ", ", ", ""); 1635 printer.println(";"); 1636 } 1637 1638 @Override visit(ModuleUsesDirective n, Void arg)1639 public void visit(ModuleUsesDirective n, Void arg) { 1640 printer.print("uses "); 1641 n.getName().accept(this, arg); 1642 printer.println(";"); 1643 } 1644 1645 @Override visit(ModuleOpensDirective n, Void arg)1646 public void visit(ModuleOpensDirective n, Void arg) { 1647 printer.print("opens "); 1648 n.getName().accept(this, arg); 1649 printPrePostFixOptionalList(n.getModuleNames(), arg, " to ", ", ", ""); 1650 printer.println(";"); 1651 } 1652 1653 @Override visit(UnparsableStmt n, Void arg)1654 public void visit(UnparsableStmt n, Void arg) { 1655 printer.print("???;"); 1656 } 1657 printOrphanCommentsBeforeThisChildNode(final Node node)1658 private void printOrphanCommentsBeforeThisChildNode(final Node node) { 1659 if (configuration.isIgnoreComments()) return; 1660 if (node instanceof Comment) return; 1661 1662 Node parent = node.getParentNode().orElse(null); 1663 if (parent == null) return; 1664 List<Node> everything = new ArrayList<>(parent.getChildNodes()); 1665 sortByBeginPosition(everything); 1666 int positionOfTheChild = -1; 1667 for (int i = 0; i < everything.size(); ++i) { // indexOf is by equality, so this is used to index by identity 1668 if (everything.get(i) == node) { 1669 positionOfTheChild = i; 1670 break; 1671 } 1672 } 1673 if (positionOfTheChild == -1) { 1674 throw new AssertionError("I am not a child of my parent."); 1675 } 1676 int positionOfPreviousChild = -1; 1677 for (int i = positionOfTheChild - 1; i >= 0 && positionOfPreviousChild == -1; i--) { 1678 if (!(everything.get(i) instanceof Comment)) positionOfPreviousChild = i; 1679 } 1680 for (int i = positionOfPreviousChild + 1; i < positionOfTheChild; i++) { 1681 Node nodeToPrint = everything.get(i); 1682 if (!(nodeToPrint instanceof Comment)) 1683 throw new RuntimeException( 1684 "Expected comment, instead " + nodeToPrint.getClass() + ". Position of previous child: " 1685 + positionOfPreviousChild + ", position of child " + positionOfTheChild); 1686 nodeToPrint.accept(this, null); 1687 } 1688 } 1689 printOrphanCommentsEnding(final Node node)1690 private void printOrphanCommentsEnding(final Node node) { 1691 if (configuration.isIgnoreComments()) return; 1692 1693 List<Node> everything = new ArrayList<>(node.getChildNodes()); 1694 sortByBeginPosition(everything); 1695 if (everything.isEmpty()) { 1696 return; 1697 } 1698 1699 int commentsAtEnd = 0; 1700 boolean findingComments = true; 1701 while (findingComments && commentsAtEnd < everything.size()) { 1702 Node last = everything.get(everything.size() - 1 - commentsAtEnd); 1703 findingComments = (last instanceof Comment); 1704 if (findingComments) { 1705 commentsAtEnd++; 1706 } 1707 } 1708 for (int i = 0; i < commentsAtEnd; i++) { 1709 everything.get(everything.size() - commentsAtEnd + i).accept(this, null); 1710 } 1711 } 1712 1713 } 1714