1 /*******************************************************************************
2  * Copyright (c) 2000, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.core.dom;
15 
16 import java.util.Iterator;
17 import java.util.List;
18 
19 import org.eclipse.jdt.core.dom.*;
20 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
21 import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
22 
23 /**
24  * Internal AST visitor for serializing an AST in a quick and dirty fashion.
25  * For various reasons the resulting string is not necessarily legal
26  * Java code; and even if it is legal Java code, it is not necessarily the string
27  * that corresponds to the given AST. Although useless for most purposes, it's
28  * fine for generating debug print strings.
29  * <p>
30  * Example usage:
31  * <code>
32  * <pre>
33  *    NaiveASTFlattener p = new NaiveASTFlattener();
34  *    node.accept(p);
35  *    String result = p.getResult();
36  * </pre>
37  * </code>
38  * Call the <code>reset</code> method to clear the previous result before reusing an
39  * existing instance.
40  * </p>
41  *
42  * @since 2.0
43  */
44 @SuppressWarnings("rawtypes")
45 public class NaiveASTFlattener extends ASTVisitor {
46 	/**
47 	 * Internal synonym for {@link AST#JLS2}. Use to alleviate
48 	 * deprecation warnings.
49 	 * @deprecated
50 	 * @since 3.4
51 	 */
52 	private static final int JLS2 = AST.JLS2;
53 
54 	/**
55 	 * Internal synonym for {@link AST#JLS3}. Use to alleviate
56 	 * deprecation warnings.
57 	 * @deprecated
58 	 * @since 3.4
59 	 */
60 	private static final int JLS3 = AST.JLS3;
61 
62 	/**
63 	 * Internal synonym for {@link AST#JLS4}. Use to alleviate
64 	 * deprecation warnings.
65 	 * @deprecated
66 	 * @since 3.10
67 	 */
68 	private static final int JLS4 = AST.JLS4;
69 
70 	/**
71 	 * Internal synonym for {@link AST#JLS8}. Use to alleviate
72 	 * deprecation warnings.
73 	 * @deprecated
74 	 * @since 3.14
75 	 */
76 	private static final int JLS8 = AST.JLS8;
77 
78 	/**
79 	 * Internal synonym for {@link AST#JLS9}. Use to alleviate
80 	 * deprecation warnings.
81 	 * @deprecated
82 	 * @since 3.14
83 	 */
84 	private static final int JLS9 = AST.JLS9;
85 
86 	/**
87 	 * The string buffer into which the serialized representation of the AST is
88 	 * written.
89 	 */
90 	protected StringBuffer buffer;
91 
92 	private int indent = 0;
93 
94 	/**
95 	 * Creates a new AST printer.
96 	 */
NaiveASTFlattener()97 	public NaiveASTFlattener() {
98 		this.buffer = new StringBuffer();
99 	}
100 
101 	/**
102 	 * Internal synonym for {@link ClassInstanceCreation#getName()}. Use to alleviate
103 	 * deprecation warnings.
104 	 * @deprecated
105 	 * @since 3.4
106 	 */
getName(ClassInstanceCreation node)107 	private Name getName(ClassInstanceCreation node) {
108 		return node.getName();
109 	}
110 
111 	/**
112 	 * Returns the string accumulated in the visit.
113 	 *
114 	 * @return the serialized
115 	 */
getResult()116 	public String getResult() {
117 		return this.buffer.toString();
118 	}
119 
120 	/**
121 	 * Internal synonym for {@link MethodDeclaration#getReturnType()}. Use to alleviate
122 	 * deprecation warnings.
123 	 * @deprecated
124 	 * @since 3.4
125 	 */
getReturnType(MethodDeclaration node)126 	private static Type getReturnType(MethodDeclaration node) {
127 		return node.getReturnType();
128 	}
129 
130 	/**
131 	 * Internal synonym for {@link TypeDeclaration#getSuperclass()}. Use to alleviate
132 	 * deprecation warnings.
133 	 * @deprecated
134 	 * @since 3.4
135 	 */
getSuperclass(TypeDeclaration node)136 	private static Name getSuperclass(TypeDeclaration node) {
137 		return node.getSuperclass();
138 	}
139 
140 	/**
141 	 * Internal synonym for {@link TypeDeclarationStatement#getTypeDeclaration()}. Use to alleviate
142 	 * deprecation warnings.
143 	 * @deprecated
144 	 * @since 3.4
145 	 */
getTypeDeclaration(TypeDeclarationStatement node)146 	private static TypeDeclaration getTypeDeclaration(TypeDeclarationStatement node) {
147 		return node.getTypeDeclaration();
148 	}
149 
150 	/**
151 	 * Internal synonym for {@link MethodDeclaration#thrownExceptions()}. Use to alleviate
152 	 * deprecation warnings.
153 	 * @deprecated
154 	 * @since 3.10
155 	 */
thrownExceptions(MethodDeclaration node)156 	private static List thrownExceptions(MethodDeclaration node) {
157 		return node.thrownExceptions();
158 	}
159 
printIndent()160 	void printIndent() {
161 		for (int i = 0; i < this.indent; i++)
162 			this.buffer.append("  "); //$NON-NLS-1$
163 	}
164 
165 	/**
166 	 * Appends the text representation of the given modifier flags, followed by a single space.
167 	 * Used for JLS2 modifiers.
168 	 *
169 	 * @param modifiers the modifier flags
170 	 */
printModifiers(int modifiers)171 	void printModifiers(int modifiers) {
172 		if (Modifier.isPublic(modifiers)) {
173 			this.buffer.append("public ");//$NON-NLS-1$
174 		}
175 		if (Modifier.isProtected(modifiers)) {
176 			this.buffer.append("protected ");//$NON-NLS-1$
177 		}
178 		if (Modifier.isPrivate(modifiers)) {
179 			this.buffer.append("private ");//$NON-NLS-1$
180 		}
181 		if (Modifier.isStatic(modifiers)) {
182 			this.buffer.append("static ");//$NON-NLS-1$
183 		}
184 		if (Modifier.isAbstract(modifiers)) {
185 			this.buffer.append("abstract ");//$NON-NLS-1$
186 		}
187 		if (Modifier.isFinal(modifiers)) {
188 			this.buffer.append("final ");//$NON-NLS-1$
189 		}
190 		if (Modifier.isSynchronized(modifiers)) {
191 			this.buffer.append("synchronized ");//$NON-NLS-1$
192 		}
193 		if (Modifier.isVolatile(modifiers)) {
194 			this.buffer.append("volatile ");//$NON-NLS-1$
195 		}
196 		if (Modifier.isNative(modifiers)) {
197 			this.buffer.append("native ");//$NON-NLS-1$
198 		}
199 		if (Modifier.isStrictfp(modifiers)) {
200 			this.buffer.append("strictfp ");//$NON-NLS-1$
201 		}
202 		if (Modifier.isTransient(modifiers)) {
203 			this.buffer.append("transient ");//$NON-NLS-1$
204 		}
205 	}
206 
207 	/**
208 	 * Appends the text representation of the given modifier flags, followed by a single space.
209 	 * Used for 3.0 modifiers and annotations.
210 	 *
211 	 * @param ext the list of modifier and annotation nodes
212 	 * (element type: <code>IExtendedModifiers</code>)
213 	 */
printModifiers(List ext)214 	void printModifiers(List ext) {
215 		for (Iterator it = ext.iterator(); it.hasNext(); ) {
216 			ASTNode p = (ASTNode) it.next();
217 			p.accept(this);
218 			this.buffer.append(" ");//$NON-NLS-1$
219 		}
220 	}
221 
printTypes(List<Type> types, String prefix)222 	private void printTypes(List<Type> types, String prefix) {
223 		if (types.size() > 0) {
224 			this.buffer.append(" " + prefix + " ");//$NON-NLS-1$ //$NON-NLS-2$
225 			Type type = types.get(0);
226 			type.accept(this);
227 			for (int i = 1, l = types.size(); i < l; ++i) {
228 				this.buffer.append(","); //$NON-NLS-1$
229 				type = types.get(0);
230 				type.accept(this);
231 			}
232 		}
233 	}
234 
235 	/**
236 	 * reference node helper function that is common to all
237 	 * the difference reference nodes.
238 	 *
239 	 * @param typeArguments list of type arguments
240 	 */
visitReferenceTypeArguments(List typeArguments)241 	private void visitReferenceTypeArguments(List typeArguments) {
242 		this.buffer.append("::");//$NON-NLS-1$
243 		if (!typeArguments.isEmpty()) {
244 			this.buffer.append('<');
245 			for (Iterator it = typeArguments.iterator(); it.hasNext(); ) {
246 				Type t = (Type) it.next();
247 				t.accept(this);
248 				if (it.hasNext()) {
249 					this.buffer.append(',');
250 				}
251 			}
252 			this.buffer.append('>');
253 		}
254 	}
255 
visitTypeAnnotations(AnnotatableType node)256 	private void visitTypeAnnotations(AnnotatableType node) {
257 		if (node.getAST().apiLevel() >= JLS8) {
258 			visitAnnotationsList(node.annotations());
259 		}
260 	}
261 
visitAnnotationsList(List annotations)262 	private void visitAnnotationsList(List annotations) {
263 		for (Iterator it = annotations.iterator(); it.hasNext(); ) {
264 			Annotation annotation = (Annotation) it.next();
265 			annotation.accept(this);
266 			this.buffer.append(' ');
267 		}
268 	}
269 
270 	/**
271 	 * Resets this printer so that it can be used again.
272 	 */
reset()273 	public void reset() {
274 		this.buffer.setLength(0);
275 	}
276 
277 	/**
278 	 * Internal synonym for {@link TypeDeclaration#superInterfaces()}. Use to alleviate
279 	 * deprecation warnings.
280 	 * @deprecated
281 	 * @since 3.4
282 	 */
superInterfaces(TypeDeclaration node)283 	private List superInterfaces(TypeDeclaration node) {
284 		return node.superInterfaces();
285 	}
286 
287 	@Override
visit(AnnotationTypeDeclaration node)288 	public boolean visit(AnnotationTypeDeclaration node) {
289 		if (node.getJavadoc() != null) {
290 			node.getJavadoc().accept(this);
291 		}
292 		printIndent();
293 		printModifiers(node.modifiers());
294 		this.buffer.append("@interface ");//$NON-NLS-1$
295 		node.getName().accept(this);
296 		this.buffer.append(" {");//$NON-NLS-1$
297 		for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
298 			BodyDeclaration d = (BodyDeclaration) it.next();
299 			d.accept(this);
300 		}
301 		this.buffer.append("}\n");//$NON-NLS-1$
302 		return false;
303 	}
304 
305 	@Override
visit(AnnotationTypeMemberDeclaration node)306 	public boolean visit(AnnotationTypeMemberDeclaration node) {
307 		if (node.getJavadoc() != null) {
308 			node.getJavadoc().accept(this);
309 		}
310 		printIndent();
311 		printModifiers(node.modifiers());
312 		node.getType().accept(this);
313 		this.buffer.append(" ");//$NON-NLS-1$
314 		node.getName().accept(this);
315 		this.buffer.append("()");//$NON-NLS-1$
316 		if (node.getDefault() != null) {
317 			this.buffer.append(" default ");//$NON-NLS-1$
318 			node.getDefault().accept(this);
319 		}
320 		this.buffer.append(";\n");//$NON-NLS-1$
321 		return false;
322 	}
323 
324 	@Override
visit(AnonymousClassDeclaration node)325 	public boolean visit(AnonymousClassDeclaration node) {
326 		this.buffer.append("{\n");//$NON-NLS-1$
327 		this.indent++;
328 		for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
329 			BodyDeclaration b = (BodyDeclaration) it.next();
330 			b.accept(this);
331 		}
332 		this.indent--;
333 		printIndent();
334 		this.buffer.append("}\n");//$NON-NLS-1$
335 		return false;
336 	}
337 
338 	@Override
visit(ArrayAccess node)339 	public boolean visit(ArrayAccess node) {
340 		node.getArray().accept(this);
341 		this.buffer.append("[");//$NON-NLS-1$
342 		node.getIndex().accept(this);
343 		this.buffer.append("]");//$NON-NLS-1$
344 		return false;
345 	}
346 
347 	@Override
visit(ArrayCreation node)348 	public boolean visit(ArrayCreation node) {
349 		this.buffer.append("new ");//$NON-NLS-1$
350 		ArrayType at = node.getType();
351 		int dims = at.getDimensions();
352 		Type elementType = at.getElementType();
353 		elementType.accept(this);
354 		for (Iterator it = node.dimensions().iterator(); it.hasNext(); ) {
355 			this.buffer.append("[");//$NON-NLS-1$
356 			Expression e = (Expression) it.next();
357 			e.accept(this);
358 			this.buffer.append("]");//$NON-NLS-1$
359 			dims--;
360 		}
361 		// add empty "[]" for each extra array dimension
362 		for (int i= 0; i < dims; i++) {
363 			this.buffer.append("[]");//$NON-NLS-1$
364 		}
365 		if (node.getInitializer() != null) {
366 			node.getInitializer().accept(this);
367 		}
368 		return false;
369 	}
370 
371 	@Override
visit(ArrayInitializer node)372 	public boolean visit(ArrayInitializer node) {
373 		this.buffer.append("{");//$NON-NLS-1$
374 		for (Iterator it = node.expressions().iterator(); it.hasNext(); ) {
375 			Expression e = (Expression) it.next();
376 			e.accept(this);
377 			if (it.hasNext()) {
378 				this.buffer.append(",");//$NON-NLS-1$
379 			}
380 		}
381 		this.buffer.append("}");//$NON-NLS-1$
382 		return false;
383 	}
384 
385 	@Override
visit(ArrayType node)386 	public boolean visit(ArrayType node) {
387 		if (node.getAST().apiLevel() < JLS8) {
388 			visitComponentType(node);
389 			this.buffer.append("[]");//$NON-NLS-1$
390 		} else {
391 			node.getElementType().accept(this);
392 			List dimensions = node.dimensions();
393 			int size = dimensions.size();
394 			for (int i = 0; i < size; i++) {
395 				Dimension aDimension = (Dimension) dimensions.get(i);
396 				aDimension.accept(this);
397 			}
398 		}
399 		return false;
400 	}
401 
402 	@Override
visit(AssertStatement node)403 	public boolean visit(AssertStatement node) {
404 		printIndent();
405 		this.buffer.append("assert ");//$NON-NLS-1$
406 		node.getExpression().accept(this);
407 		if (node.getMessage() != null) {
408 			this.buffer.append(" : ");//$NON-NLS-1$
409 			node.getMessage().accept(this);
410 		}
411 		this.buffer.append(";\n");//$NON-NLS-1$
412 		return false;
413 	}
414 
415 	@Override
visit(Assignment node)416 	public boolean visit(Assignment node) {
417 		node.getLeftHandSide().accept(this);
418 		this.buffer.append(node.getOperator().toString());
419 		node.getRightHandSide().accept(this);
420 		return false;
421 	}
422 
423 	@Override
visit(Block node)424 	public boolean visit(Block node) {
425 		this.buffer.append("{\n");//$NON-NLS-1$
426 		this.indent++;
427 		for (Iterator it = node.statements().iterator(); it.hasNext(); ) {
428 			Statement s = (Statement) it.next();
429 			s.accept(this);
430 		}
431 		this.indent--;
432 		printIndent();
433 		this.buffer.append("}\n");//$NON-NLS-1$
434 		return false;
435 	}
436 
437 	@Override
visit(BlockComment node)438 	public boolean visit(BlockComment node) {
439 		printIndent();
440 		this.buffer.append("/* */");//$NON-NLS-1$
441 		return false;
442 	}
443 
444 	@Override
visit(BooleanLiteral node)445 	public boolean visit(BooleanLiteral node) {
446 		if (node.booleanValue() == true) {
447 			this.buffer.append("true");//$NON-NLS-1$
448 		} else {
449 			this.buffer.append("false");//$NON-NLS-1$
450 		}
451 		return false;
452 	}
453 
454 	@Override
visit(BreakStatement node)455 	public boolean visit(BreakStatement node) {
456 		printIndent();
457 		this.buffer.append("break");//$NON-NLS-1$
458 		if (node.getLabel() != null) {
459 			this.buffer.append(" ");//$NON-NLS-1$
460 			node.getLabel().accept(this);
461 		}
462 		this.buffer.append(";\n");//$NON-NLS-1$
463 		return false;
464 	}
465 
466 	@Override
visit(CastExpression node)467 	public boolean visit(CastExpression node) {
468 		this.buffer.append("(");//$NON-NLS-1$
469 		node.getType().accept(this);
470 		this.buffer.append(")");//$NON-NLS-1$
471 		node.getExpression().accept(this);
472 		return false;
473 	}
474 
475 	@Override
visit(CatchClause node)476 	public boolean visit(CatchClause node) {
477 		this.buffer.append("catch (");//$NON-NLS-1$
478 		node.getException().accept(this);
479 		this.buffer.append(") ");//$NON-NLS-1$
480 		node.getBody().accept(this);
481 		return false;
482 	}
483 
484 	@Override
visit(CharacterLiteral node)485 	public boolean visit(CharacterLiteral node) {
486 		this.buffer.append(node.getEscapedValue());
487 		return false;
488 	}
489 
490 	@Override
visit(ClassInstanceCreation node)491 	public boolean visit(ClassInstanceCreation node) {
492 		if (node.getExpression() != null) {
493 			node.getExpression().accept(this);
494 			this.buffer.append(".");//$NON-NLS-1$
495 		}
496 		this.buffer.append("new ");//$NON-NLS-1$
497 		if (node.getAST().apiLevel() == JLS2) {
498 			getName(node).accept(this);
499 		}
500 		if (node.getAST().apiLevel() >= JLS3) {
501 			if (!node.typeArguments().isEmpty()) {
502 				this.buffer.append("<");//$NON-NLS-1$
503 				for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
504 					Type t = (Type) it.next();
505 					t.accept(this);
506 					if (it.hasNext()) {
507 						this.buffer.append(",");//$NON-NLS-1$
508 					}
509 				}
510 				this.buffer.append(">");//$NON-NLS-1$
511 			}
512 			node.getType().accept(this);
513 		}
514 		this.buffer.append("(");//$NON-NLS-1$
515 		for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
516 			Expression e = (Expression) it.next();
517 			e.accept(this);
518 			if (it.hasNext()) {
519 				this.buffer.append(",");//$NON-NLS-1$
520 			}
521 		}
522 		this.buffer.append(")");//$NON-NLS-1$
523 		if (node.getAnonymousClassDeclaration() != null) {
524 			node.getAnonymousClassDeclaration().accept(this);
525 		}
526 		return false;
527 	}
528 
529 	@Override
visit(CompilationUnit node)530 	public boolean visit(CompilationUnit node) {
531 		if (node.getAST().apiLevel() >= JLS9) {
532 			if (node.getModule() != null) {
533 				node.getModule().accept(this);
534 			}
535 		}
536 		if (node.getPackage() != null) {
537 			node.getPackage().accept(this);
538 		}
539 		for (Iterator it = node.imports().iterator(); it.hasNext(); ) {
540 			ImportDeclaration d = (ImportDeclaration) it.next();
541 			d.accept(this);
542 		}
543 		for (Iterator it = node.types().iterator(); it.hasNext(); ) {
544 			AbstractTypeDeclaration d = (AbstractTypeDeclaration) it.next();
545 			d.accept(this);
546 		}
547 		return false;
548 	}
549 
550 	@Override
visit(ConditionalExpression node)551 	public boolean visit(ConditionalExpression node) {
552 		node.getExpression().accept(this);
553 		this.buffer.append(" ? ");//$NON-NLS-1$
554 		node.getThenExpression().accept(this);
555 		this.buffer.append(" : ");//$NON-NLS-1$
556 		node.getElseExpression().accept(this);
557 		return false;
558 	}
559 
560 	@Override
visit(ConstructorInvocation node)561 	public boolean visit(ConstructorInvocation node) {
562 		printIndent();
563 		if (node.getAST().apiLevel() >= JLS3) {
564 			if (!node.typeArguments().isEmpty()) {
565 				this.buffer.append("<");//$NON-NLS-1$
566 				for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
567 					Type t = (Type) it.next();
568 					t.accept(this);
569 					if (it.hasNext()) {
570 						this.buffer.append(",");//$NON-NLS-1$
571 					}
572 				}
573 				this.buffer.append(">");//$NON-NLS-1$
574 			}
575 		}
576 		this.buffer.append("this(");//$NON-NLS-1$
577 		for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
578 			Expression e = (Expression) it.next();
579 			e.accept(this);
580 			if (it.hasNext()) {
581 				this.buffer.append(",");//$NON-NLS-1$
582 			}
583 		}
584 		this.buffer.append(");\n");//$NON-NLS-1$
585 		return false;
586 	}
587 
588 	@Override
visit(ContinueStatement node)589 	public boolean visit(ContinueStatement node) {
590 		printIndent();
591 		this.buffer.append("continue");//$NON-NLS-1$
592 		if (node.getLabel() != null) {
593 			this.buffer.append(" ");//$NON-NLS-1$
594 			node.getLabel().accept(this);
595 		}
596 		this.buffer.append(";\n");//$NON-NLS-1$
597 		return false;
598 	}
599 
600 	@Override
visit(CreationReference node)601 	public boolean visit(CreationReference node) {
602 		node.getType().accept(this);
603 		visitReferenceTypeArguments(node.typeArguments());
604 		this.buffer.append("new");//$NON-NLS-1$
605 		return false;
606 	}
607 
608 	@Override
visit(Dimension node)609 	public boolean visit(Dimension node) {
610 		List annotations = node.annotations();
611 		if (annotations.size() > 0)
612 			this.buffer.append(' ');
613 		visitAnnotationsList(annotations);
614 		this.buffer.append("[]"); //$NON-NLS-1$
615 		return false;
616 	}
617 
618 	@Override
visit(DoStatement node)619 	public boolean visit(DoStatement node) {
620 		printIndent();
621 		this.buffer.append("do ");//$NON-NLS-1$
622 		node.getBody().accept(this);
623 		this.buffer.append(" while (");//$NON-NLS-1$
624 		node.getExpression().accept(this);
625 		this.buffer.append(");\n");//$NON-NLS-1$
626 		return false;
627 	}
628 
629 	@Override
visit(EmptyStatement node)630 	public boolean visit(EmptyStatement node) {
631 		printIndent();
632 		this.buffer.append(";\n");//$NON-NLS-1$
633 		return false;
634 	}
635 
636 	@Override
visit(EnhancedForStatement node)637 	public boolean visit(EnhancedForStatement node) {
638 		printIndent();
639 		this.buffer.append("for (");//$NON-NLS-1$
640 		node.getParameter().accept(this);
641 		this.buffer.append(" : ");//$NON-NLS-1$
642 		node.getExpression().accept(this);
643 		this.buffer.append(") ");//$NON-NLS-1$
644 		node.getBody().accept(this);
645 		return false;
646 	}
647 
648 	@Override
visit(EnumConstantDeclaration node)649 	public boolean visit(EnumConstantDeclaration node) {
650 		if (node.getJavadoc() != null) {
651 			node.getJavadoc().accept(this);
652 		}
653 		printIndent();
654 		printModifiers(node.modifiers());
655 		node.getName().accept(this);
656 		if (!node.arguments().isEmpty()) {
657 			this.buffer.append("(");//$NON-NLS-1$
658 			for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
659 				Expression e = (Expression) it.next();
660 				e.accept(this);
661 				if (it.hasNext()) {
662 					this.buffer.append(",");//$NON-NLS-1$
663 				}
664 			}
665 			this.buffer.append(")");//$NON-NLS-1$
666 		}
667 		if (node.getAnonymousClassDeclaration() != null) {
668 			node.getAnonymousClassDeclaration().accept(this);
669 		}
670 		return false;
671 	}
672 
673 	@Override
visit(EnumDeclaration node)674 	public boolean visit(EnumDeclaration node) {
675 		if (node.getJavadoc() != null) {
676 			node.getJavadoc().accept(this);
677 		}
678 		printIndent();
679 		printModifiers(node.modifiers());
680 		this.buffer.append("enum ");//$NON-NLS-1$
681 		node.getName().accept(this);
682 		this.buffer.append(" ");//$NON-NLS-1$
683 		if (!node.superInterfaceTypes().isEmpty()) {
684 			this.buffer.append("implements ");//$NON-NLS-1$
685 			for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) {
686 				Type t = (Type) it.next();
687 				t.accept(this);
688 				if (it.hasNext()) {
689 					this.buffer.append(", ");//$NON-NLS-1$
690 				}
691 			}
692 			this.buffer.append(" ");//$NON-NLS-1$
693 		}
694 		this.buffer.append("{");//$NON-NLS-1$
695 		for (Iterator it = node.enumConstants().iterator(); it.hasNext(); ) {
696 			EnumConstantDeclaration d = (EnumConstantDeclaration) it.next();
697 			d.accept(this);
698 			// enum constant declarations do not include punctuation
699 			if (it.hasNext()) {
700 				// enum constant declarations are separated by commas
701 				this.buffer.append(", ");//$NON-NLS-1$
702 			}
703 		}
704 		if (!node.bodyDeclarations().isEmpty()) {
705 			this.buffer.append("; ");//$NON-NLS-1$
706 			for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
707 				BodyDeclaration d = (BodyDeclaration) it.next();
708 				d.accept(this);
709 				// other body declarations include trailing punctuation
710 			}
711 		}
712 		this.buffer.append("}\n");//$NON-NLS-1$
713 		return false;
714 	}
715 
716 	@Override
visit(ExportsDirective node)717 	public boolean visit(ExportsDirective node) {
718 		return visit(node, "exports"); //$NON-NLS-1$
719 	}
720 
721 	@Override
visit(ExpressionMethodReference node)722 	public boolean visit(ExpressionMethodReference node) {
723 		node.getExpression().accept(this);
724 		visitReferenceTypeArguments(node.typeArguments());
725 		node.getName().accept(this);
726 		return false;
727 	}
728 
729 	@Override
visit(ExpressionStatement node)730 	public boolean visit(ExpressionStatement node) {
731 		printIndent();
732 		node.getExpression().accept(this);
733 		this.buffer.append(";\n");//$NON-NLS-1$
734 		return false;
735 	}
736 
737 	@Override
visit(FieldAccess node)738 	public boolean visit(FieldAccess node) {
739 		node.getExpression().accept(this);
740 		this.buffer.append(".");//$NON-NLS-1$
741 		node.getName().accept(this);
742 		return false;
743 	}
744 
745 	@Override
visit(FieldDeclaration node)746 	public boolean visit(FieldDeclaration node) {
747 		if (node.getJavadoc() != null) {
748 			node.getJavadoc().accept(this);
749 		}
750 		printIndent();
751 		if (node.getAST().apiLevel() == JLS2) {
752 			printModifiers(node.getModifiers());
753 		}
754 		if (node.getAST().apiLevel() >= JLS3) {
755 			printModifiers(node.modifiers());
756 		}
757 		node.getType().accept(this);
758 		this.buffer.append(" ");//$NON-NLS-1$
759 		for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
760 			VariableDeclarationFragment f = (VariableDeclarationFragment) it.next();
761 			f.accept(this);
762 			if (it.hasNext()) {
763 				this.buffer.append(", ");//$NON-NLS-1$
764 			}
765 		}
766 		this.buffer.append(";\n");//$NON-NLS-1$
767 		return false;
768 	}
769 
770 	@Override
visit(ForStatement node)771 	public boolean visit(ForStatement node) {
772 		printIndent();
773 		this.buffer.append("for (");//$NON-NLS-1$
774 		for (Iterator it = node.initializers().iterator(); it.hasNext(); ) {
775 			Expression e = (Expression) it.next();
776 			e.accept(this);
777 			if (it.hasNext()) this.buffer.append(", ");//$NON-NLS-1$
778 		}
779 		this.buffer.append("; ");//$NON-NLS-1$
780 		if (node.getExpression() != null) {
781 			node.getExpression().accept(this);
782 		}
783 		this.buffer.append("; ");//$NON-NLS-1$
784 		for (Iterator it = node.updaters().iterator(); it.hasNext(); ) {
785 			Expression e = (Expression) it.next();
786 			e.accept(this);
787 			if (it.hasNext()) this.buffer.append(", ");//$NON-NLS-1$
788 		}
789 		this.buffer.append(") ");//$NON-NLS-1$
790 		node.getBody().accept(this);
791 		return false;
792 	}
793 
794 	@Override
visit(IfStatement node)795 	public boolean visit(IfStatement node) {
796 		printIndent();
797 		this.buffer.append("if (");//$NON-NLS-1$
798 		node.getExpression().accept(this);
799 		this.buffer.append(") ");//$NON-NLS-1$
800 		node.getThenStatement().accept(this);
801 		if (node.getElseStatement() != null) {
802 			this.buffer.append(" else ");//$NON-NLS-1$
803 			node.getElseStatement().accept(this);
804 		}
805 		return false;
806 	}
807 
808 	@Override
visit(ImportDeclaration node)809 	public boolean visit(ImportDeclaration node) {
810 		printIndent();
811 		this.buffer.append("import ");//$NON-NLS-1$
812 		if (node.getAST().apiLevel() >= JLS3) {
813 			if (node.isStatic()) {
814 				this.buffer.append("static ");//$NON-NLS-1$
815 			}
816 		}
817 		node.getName().accept(this);
818 		if (node.isOnDemand()) {
819 			this.buffer.append(".*");//$NON-NLS-1$
820 		}
821 		this.buffer.append(";\n");//$NON-NLS-1$
822 		return false;
823 	}
824 
825 	@Override
visit(InfixExpression node)826 	public boolean visit(InfixExpression node) {
827 		node.getLeftOperand().accept(this);
828 		this.buffer.append(' ');  // for cases like x= i - -1; or x= i++ + ++i;
829 		this.buffer.append(node.getOperator().toString());
830 		this.buffer.append(' ');
831 		node.getRightOperand().accept(this);
832 		final List extendedOperands = node.extendedOperands();
833 		if (extendedOperands.size() != 0) {
834 			this.buffer.append(' ');
835 			for (Iterator it = extendedOperands.iterator(); it.hasNext(); ) {
836 				this.buffer.append(node.getOperator().toString()).append(' ');
837 				Expression e = (Expression) it.next();
838 				e.accept(this);
839 			}
840 		}
841 		return false;
842 	}
843 
844 	@Override
visit(Initializer node)845 	public boolean visit(Initializer node) {
846 		if (node.getJavadoc() != null) {
847 			node.getJavadoc().accept(this);
848 		}
849 		if (node.getAST().apiLevel() == JLS2) {
850 			printModifiers(node.getModifiers());
851 		}
852 		if (node.getAST().apiLevel() >= JLS3) {
853 			printModifiers(node.modifiers());
854 		}
855 		node.getBody().accept(this);
856 		return false;
857 	}
858 
859 	@Override
visit(InstanceofExpression node)860 	public boolean visit(InstanceofExpression node) {
861 		node.getLeftOperand().accept(this);
862 		this.buffer.append(" instanceof ");//$NON-NLS-1$
863 		if (DOMASTUtil.isInstanceofExpressionPatternSupported(node.getAST()) && node.getPatternVariable()!= null) {
864 			node.getPatternVariable().accept(this);
865 		} else {
866 			node.getRightOperand().accept(this);
867 		}
868 		return false;
869 	}
870 
871 	@Override
visit(IntersectionType node)872 	public boolean visit(IntersectionType node) {
873 		for (Iterator it = node.types().iterator(); it.hasNext(); ) {
874 			Type t = (Type) it.next();
875 			t.accept(this);
876 			if (it.hasNext()) {
877 				this.buffer.append(" & "); //$NON-NLS-1$
878 			}
879 		}
880 		return false;
881 	}
882 
883 	@Override
visit(Javadoc node)884 	public boolean visit(Javadoc node) {
885 		printIndent();
886 		this.buffer.append("/** ");//$NON-NLS-1$
887 		for (Iterator it = node.tags().iterator(); it.hasNext(); ) {
888 			ASTNode e = (ASTNode) it.next();
889 			e.accept(this);
890 		}
891 		this.buffer.append("\n */\n");//$NON-NLS-1$
892 		return false;
893 	}
894 
895 	@Override
visit(LabeledStatement node)896 	public boolean visit(LabeledStatement node) {
897 		printIndent();
898 		node.getLabel().accept(this);
899 		this.buffer.append(": ");//$NON-NLS-1$
900 		node.getBody().accept(this);
901 		return false;
902 	}
903 
904 	@Override
visit(LambdaExpression node)905 	public boolean visit(LambdaExpression node) {
906 		boolean hasParentheses = node.hasParentheses();
907 		if (hasParentheses)
908 			this.buffer.append('(');
909 		for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
910 			VariableDeclaration v = (VariableDeclaration) it.next();
911 			v.accept(this);
912 			if (it.hasNext()) {
913 				this.buffer.append(",");//$NON-NLS-1$
914 			}
915 		}
916 		if (hasParentheses)
917 			this.buffer.append(')');
918 		this.buffer.append(" -> "); //$NON-NLS-1$
919 		node.getBody().accept(this);
920 		return false;
921 	}
922 
923 	@Override
visit(LineComment node)924 	public boolean visit(LineComment node) {
925 		this.buffer.append("//\n");//$NON-NLS-1$
926 		return false;
927 	}
928 
929 	@Override
visit(MarkerAnnotation node)930 	public boolean visit(MarkerAnnotation node) {
931 		this.buffer.append("@");//$NON-NLS-1$
932 		node.getTypeName().accept(this);
933 		return false;
934 	}
935 
936 	@Override
visit(MemberRef node)937 	public boolean visit(MemberRef node) {
938 		if (node.getQualifier() != null) {
939 			node.getQualifier().accept(this);
940 		}
941 		this.buffer.append("#");//$NON-NLS-1$
942 		node.getName().accept(this);
943 		return false;
944 	}
945 
946 	@Override
visit(MemberValuePair node)947 	public boolean visit(MemberValuePair node) {
948 		node.getName().accept(this);
949 		this.buffer.append("=");//$NON-NLS-1$
950 		node.getValue().accept(this);
951 		return false;
952 	}
953 
954 	@Override
visit(MethodDeclaration node)955 	public boolean visit(MethodDeclaration node) {
956 		if (node.getJavadoc() != null) {
957 			node.getJavadoc().accept(this);
958 		}
959 		printIndent();
960 		if (node.getAST().apiLevel() == JLS2) {
961 			printModifiers(node.getModifiers());
962 		}
963 		if (node.getAST().apiLevel() >= JLS3) {
964 			printModifiers(node.modifiers());
965 			if (!node.typeParameters().isEmpty()) {
966 				this.buffer.append("<");//$NON-NLS-1$
967 				for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) {
968 					TypeParameter t = (TypeParameter) it.next();
969 					t.accept(this);
970 					if (it.hasNext()) {
971 						this.buffer.append(",");//$NON-NLS-1$
972 					}
973 				}
974 				this.buffer.append(">");//$NON-NLS-1$
975 			}
976 		}
977 		if (!node.isConstructor()){
978 			if (node.getAST().apiLevel() == JLS2) {
979 				getReturnType(node).accept(this);
980 			} else {
981 				if (node.getReturnType2() != null) {
982 					node.getReturnType2().accept(this);
983 				} else {
984 					// methods really ought to have a return type
985 					this.buffer.append("void");//$NON-NLS-1$
986 				}
987 			}
988 			this.buffer.append(" ");//$NON-NLS-1$
989 		}
990 		node.getName().accept(this);
991 		if (!(DOMASTUtil.isRecordDeclarationSupported(node.getAST()) && node.isCompactConstructor())) {
992 			this.buffer.append("(");//$NON-NLS-1$
993 			if (node.getAST().apiLevel() >= JLS8) {
994 				Type receiverType = node.getReceiverType();
995 				if (receiverType != null) {
996 					receiverType.accept(this);
997 					this.buffer.append(' ');
998 					SimpleName qualifier = node.getReceiverQualifier();
999 					if (qualifier != null) {
1000 						qualifier.accept(this);
1001 						this.buffer.append('.');
1002 					}
1003 					this.buffer.append("this"); //$NON-NLS-1$
1004 					if (node.parameters().size() > 0) {
1005 						this.buffer.append(',');
1006 					}
1007 				}
1008 			}
1009 			for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
1010 				SingleVariableDeclaration v = (SingleVariableDeclaration) it.next();
1011 				v.accept(this);
1012 				if (it.hasNext()) {
1013 					this.buffer.append(",");//$NON-NLS-1$
1014 				}
1015 			}
1016 			this.buffer.append(")");//$NON-NLS-1$
1017 		}
1018 		int size = node.getExtraDimensions();
1019 		if (node.getAST().apiLevel() >= JLS8) {
1020 			List dimensions = node.extraDimensions();
1021 			for (int i = 0; i < size; i++) {
1022 				visit((Dimension) dimensions.get(i));
1023 			}
1024 		} else {
1025 			for (int i = 0; i < size; i++) {
1026 				this.buffer.append("[]"); //$NON-NLS-1$
1027 			}
1028 		}
1029 		if (node.getAST().apiLevel() < JLS8) {
1030 			if (!thrownExceptions(node).isEmpty()) {
1031 				this.buffer.append(" throws ");//$NON-NLS-1$
1032 				for (Iterator it = thrownExceptions(node).iterator(); it.hasNext(); ) {
1033 					Name n = (Name) it.next();
1034 					n.accept(this);
1035 					if (it.hasNext()) {
1036 						this.buffer.append(", ");//$NON-NLS-1$
1037 					}
1038 				}
1039 				this.buffer.append(" ");//$NON-NLS-1$
1040 			}
1041 		} else {
1042 			if (!node.thrownExceptionTypes().isEmpty()) {
1043 				this.buffer.append(" throws ");//$NON-NLS-1$
1044 				for (Iterator it = node.thrownExceptionTypes().iterator(); it.hasNext(); ) {
1045 					Type n = (Type) it.next();
1046 					n.accept(this);
1047 					if (it.hasNext()) {
1048 						this.buffer.append(", ");//$NON-NLS-1$
1049 					}
1050 				}
1051 				this.buffer.append(" ");//$NON-NLS-1$
1052 			}
1053 		}
1054 		if (node.getBody() == null) {
1055 			this.buffer.append(";\n");//$NON-NLS-1$
1056 		} else {
1057 			node.getBody().accept(this);
1058 		}
1059 		return false;
1060 	}
1061 
1062 	@Override
visit(MethodInvocation node)1063 	public boolean visit(MethodInvocation node) {
1064 		if (node.getExpression() != null) {
1065 			node.getExpression().accept(this);
1066 			this.buffer.append(".");//$NON-NLS-1$
1067 		}
1068 		if (node.getAST().apiLevel() >= JLS3) {
1069 			if (!node.typeArguments().isEmpty()) {
1070 				this.buffer.append("<");//$NON-NLS-1$
1071 				for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
1072 					Type t = (Type) it.next();
1073 					t.accept(this);
1074 					if (it.hasNext()) {
1075 						this.buffer.append(",");//$NON-NLS-1$
1076 					}
1077 				}
1078 				this.buffer.append(">");//$NON-NLS-1$
1079 			}
1080 		}
1081 		node.getName().accept(this);
1082 		this.buffer.append("(");//$NON-NLS-1$
1083 		for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
1084 			Expression e = (Expression) it.next();
1085 			e.accept(this);
1086 			if (it.hasNext()) {
1087 				this.buffer.append(",");//$NON-NLS-1$
1088 			}
1089 		}
1090 		this.buffer.append(")");//$NON-NLS-1$
1091 		return false;
1092 	}
1093 
1094 	@Override
visit(MethodRef node)1095 	public boolean visit(MethodRef node) {
1096 		if (node.getQualifier() != null) {
1097 			node.getQualifier().accept(this);
1098 		}
1099 		this.buffer.append("#");//$NON-NLS-1$
1100 		node.getName().accept(this);
1101 		this.buffer.append("(");//$NON-NLS-1$
1102 		for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
1103 			MethodRefParameter e = (MethodRefParameter) it.next();
1104 			e.accept(this);
1105 			if (it.hasNext()) {
1106 				this.buffer.append(",");//$NON-NLS-1$
1107 			}
1108 		}
1109 		this.buffer.append(")");//$NON-NLS-1$
1110 		return false;
1111 	}
1112 
1113 	@Override
visit(MethodRefParameter node)1114 	public boolean visit(MethodRefParameter node) {
1115 		node.getType().accept(this);
1116 		if (node.getAST().apiLevel() >= JLS3) {
1117 			if (node.isVarargs()) {
1118 				this.buffer.append("...");//$NON-NLS-1$
1119 			}
1120 		}
1121 		if (node.getName() != null) {
1122 			this.buffer.append(" ");//$NON-NLS-1$
1123 			node.getName().accept(this);
1124 		}
1125 		return false;
1126 	}
1127 
1128 	@Override
visit(Modifier node)1129 	public boolean visit(Modifier node) {
1130 		this.buffer.append(node.getKeyword().toString());
1131 		return false;
1132 	}
1133 
1134 	@Override
visit(ModuleDeclaration node)1135 	public boolean visit(ModuleDeclaration node) {
1136 		if (node.getJavadoc() != null) {
1137 			node.getJavadoc().accept(this);
1138 		}
1139 		printModifiers(node.annotations());
1140 		if (node.isOpen())
1141 			this.buffer.append("open "); //$NON-NLS-1$
1142 		this.buffer.append("module"); //$NON-NLS-1$
1143 		this.buffer.append(" "); //$NON-NLS-1$
1144 		node.getName().accept(this);
1145 		this.buffer.append(" {\n"); //$NON-NLS-1$
1146 		this.indent++;
1147 		for (ModuleDirective stmt : (List<ModuleDirective>)node.moduleStatements()) {
1148 			stmt.accept(this);
1149 		}
1150 		this.indent--;
1151 		this.buffer.append("}"); //$NON-NLS-1$
1152 		return false;
1153 	}
1154 
1155 	@Override
1156 	/*
1157 	 * @see ASTVisitor#visit(ModuleModifier)
1158 	 * @since 3.14
1159 	 */
visit(ModuleModifier node)1160 	public boolean visit(ModuleModifier node) {
1161 		this.buffer.append(node.getKeyword().toString());
1162 		return false;
1163 	}
1164 
visit(ModulePackageAccess node, String keyword)1165 	private boolean visit(ModulePackageAccess node, String keyword) {
1166 		printIndent();
1167 		this.buffer.append(keyword);
1168 		this.buffer.append(" ");//$NON-NLS-1$
1169 		node.getName().accept(this);
1170 		printTypes(node.modules(), "to"); //$NON-NLS-1$
1171 		this.buffer.append(";\n");//$NON-NLS-1$
1172 		return false;
1173 	}
1174 
1175 	@Override
visit(NameQualifiedType node)1176 	public boolean visit(NameQualifiedType node) {
1177 		node.getQualifier().accept(this);
1178 		this.buffer.append('.');
1179 		visitTypeAnnotations(node);
1180 		node.getName().accept(this);
1181 		return false;
1182 	}
1183 
1184 	@Override
visit(NormalAnnotation node)1185 	public boolean visit(NormalAnnotation node) {
1186 		this.buffer.append("@");//$NON-NLS-1$
1187 		node.getTypeName().accept(this);
1188 		this.buffer.append("(");//$NON-NLS-1$
1189 		for (Iterator it = node.values().iterator(); it.hasNext(); ) {
1190 			MemberValuePair p = (MemberValuePair) it.next();
1191 			p.accept(this);
1192 			if (it.hasNext()) {
1193 				this.buffer.append(",");//$NON-NLS-1$
1194 			}
1195 		}
1196 		this.buffer.append(")");//$NON-NLS-1$
1197 		return false;
1198 	}
1199 
1200 	@Override
visit(NullLiteral node)1201 	public boolean visit(NullLiteral node) {
1202 		this.buffer.append("null");//$NON-NLS-1$
1203 		return false;
1204 	}
1205 
1206 	@Override
visit(NumberLiteral node)1207 	public boolean visit(NumberLiteral node) {
1208 		this.buffer.append(node.getToken());
1209 		return false;
1210 	}
1211 
1212 	@Override
visit(OpensDirective node)1213 	public boolean visit(OpensDirective node) {
1214 		return visit(node, "opens"); //$NON-NLS-1$
1215 	}
1216 
1217 	@Override
visit(PackageDeclaration node)1218 	public boolean visit(PackageDeclaration node) {
1219 		if (node.getAST().apiLevel() >= JLS3) {
1220 			if (node.getJavadoc() != null) {
1221 				node.getJavadoc().accept(this);
1222 			}
1223 			for (Iterator it = node.annotations().iterator(); it.hasNext(); ) {
1224 				Annotation p = (Annotation) it.next();
1225 				p.accept(this);
1226 				this.buffer.append(" ");//$NON-NLS-1$
1227 			}
1228 		}
1229 		printIndent();
1230 		this.buffer.append("package ");//$NON-NLS-1$
1231 		node.getName().accept(this);
1232 		this.buffer.append(";\n");//$NON-NLS-1$
1233 		return false;
1234 	}
1235 
1236 	@Override
visit(ParameterizedType node)1237 	public boolean visit(ParameterizedType node) {
1238 		node.getType().accept(this);
1239 		this.buffer.append("<");//$NON-NLS-1$
1240 		for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
1241 			Type t = (Type) it.next();
1242 			t.accept(this);
1243 			if (it.hasNext()) {
1244 				this.buffer.append(",");//$NON-NLS-1$
1245 			}
1246 		}
1247 		this.buffer.append(">");//$NON-NLS-1$
1248 		return false;
1249 	}
1250 
1251 	@Override
visit(ParenthesizedExpression node)1252 	public boolean visit(ParenthesizedExpression node) {
1253 		this.buffer.append("(");//$NON-NLS-1$
1254 		node.getExpression().accept(this);
1255 		this.buffer.append(")");//$NON-NLS-1$
1256 		return false;
1257 	}
1258 
1259 	@Override
visit(PostfixExpression node)1260 	public boolean visit(PostfixExpression node) {
1261 		node.getOperand().accept(this);
1262 		this.buffer.append(node.getOperator().toString());
1263 		return false;
1264 	}
1265 
1266 	@Override
visit(PrefixExpression node)1267 	public boolean visit(PrefixExpression node) {
1268 		this.buffer.append(node.getOperator().toString());
1269 		node.getOperand().accept(this);
1270 		return false;
1271 	}
1272 
1273 	@Override
visit(PrimitiveType node)1274 	public boolean visit(PrimitiveType node) {
1275 		visitTypeAnnotations(node);
1276 		this.buffer.append(node.getPrimitiveTypeCode().toString());
1277 		return false;
1278 	}
1279 
1280 	@Override
visit(ProvidesDirective node)1281 	public boolean visit(ProvidesDirective node) {
1282 		printIndent();
1283 		this.buffer.append("provides");//$NON-NLS-1$
1284 		this.buffer.append(" ");//$NON-NLS-1$
1285 		node.getName().accept(this);
1286 		printTypes(node.implementations(), "with"); //$NON-NLS-1$
1287 		this.buffer.append(";\n");//$NON-NLS-1$
1288 		return false;
1289 	}
1290 
1291 	@Override
visit(QualifiedName node)1292 	public boolean visit(QualifiedName node) {
1293 		node.getQualifier().accept(this);
1294 		this.buffer.append(".");//$NON-NLS-1$
1295 		node.getName().accept(this);
1296 		return false;
1297 	}
1298 
1299 	@Override
visit(QualifiedType node)1300 	public boolean visit(QualifiedType node) {
1301 		node.getQualifier().accept(this);
1302 		this.buffer.append(".");//$NON-NLS-1$
1303 		visitTypeAnnotations(node);
1304 		node.getName().accept(this);
1305 		return false;
1306 	}
1307 
1308 	@Override
visit(RecordDeclaration node)1309 	public boolean visit(RecordDeclaration node) {
1310 		if (node.getJavadoc() != null) {
1311 			node.getJavadoc().accept(this);
1312 		}
1313 		printIndent();
1314 		printModifiers(node.modifiers());
1315 		this.buffer.append("record ");//$NON-NLS-1$
1316 		node.getName().accept(this);
1317 		this.buffer.append(" ");//$NON-NLS-1$
1318 
1319 		if (!node.typeParameters().isEmpty()) {
1320 			this.buffer.append("<");//$NON-NLS-1$
1321 			for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) {
1322 				TypeParameter t = (TypeParameter) it.next();
1323 				t.accept(this);
1324 				if (it.hasNext()) {
1325 					this.buffer.append(",");//$NON-NLS-1$
1326 				}
1327 			}
1328 			this.buffer.append(">");//$NON-NLS-1$
1329 		}
1330 		this.buffer.append(" ");//$NON-NLS-1$
1331 		this.buffer.append("(");//$NON-NLS-1$
1332 		for (Iterator it = node.recordComponents().iterator(); it.hasNext(); ) {
1333 			SingleVariableDeclaration v = (SingleVariableDeclaration) it.next();
1334 			v.accept(this);
1335 			if (it.hasNext()) {
1336 				this.buffer.append(",");//$NON-NLS-1$
1337 			}
1338 		}
1339 		this.buffer.append(")");//$NON-NLS-1$
1340 		if (!node.superInterfaceTypes().isEmpty()) {
1341 			this.buffer.append(" implements ");//$NON-NLS-1$
1342 			for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) {
1343 				Type t = (Type) it.next();
1344 				t.accept(this);
1345 				if (it.hasNext()) {
1346 					this.buffer.append(", ");//$NON-NLS-1$
1347 				}
1348 			}
1349 			this.buffer.append(" ");//$NON-NLS-1$
1350 		}
1351 		this.buffer.append("{");//$NON-NLS-1$
1352 		if (!node.bodyDeclarations().isEmpty()) {
1353 			this.buffer.append("\n");//$NON-NLS-1$
1354 			for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
1355 				BodyDeclaration d = (BodyDeclaration) it.next();
1356 				d.accept(this);
1357 				// other body declarations include trailing punctuation
1358 			}
1359 		}
1360 		this.buffer.append("}\n");//$NON-NLS-1$
1361 		return false;
1362 	}
1363 
1364 	@Override
visit(RequiresDirective node)1365 	public boolean visit(RequiresDirective node) {
1366 		printIndent();
1367 		this.buffer.append("requires");//$NON-NLS-1$
1368 		this.buffer.append(" ");//$NON-NLS-1$
1369 		printModifiers(node.modifiers());
1370 		node.getName().accept(this);
1371 		this.buffer.append(";\n");//$NON-NLS-1$
1372 		return false;
1373 	}
1374 
1375 	@Override
visit(ReturnStatement node)1376 	public boolean visit(ReturnStatement node) {
1377 		printIndent();
1378 		this.buffer.append("return");//$NON-NLS-1$
1379 		if (node.getExpression() != null) {
1380 			this.buffer.append(" ");//$NON-NLS-1$
1381 			node.getExpression().accept(this);
1382 		}
1383 		this.buffer.append(";\n");//$NON-NLS-1$
1384 		return false;
1385 	}
1386 
1387 	@Override
visit(SimpleName node)1388 	public boolean visit(SimpleName node) {
1389 		this.buffer.append(node.getIdentifier());
1390 		return false;
1391 	}
1392 
1393 	@Override
visit(SimpleType node)1394 	public boolean visit(SimpleType node) {
1395 		visitTypeAnnotations(node);
1396 		node.getName().accept(this);
1397 		return false;
1398 	}
1399 
1400 	@Override
visit(SingleMemberAnnotation node)1401 	public boolean visit(SingleMemberAnnotation node) {
1402 		this.buffer.append("@");//$NON-NLS-1$
1403 		node.getTypeName().accept(this);
1404 		this.buffer.append("(");//$NON-NLS-1$
1405 		node.getValue().accept(this);
1406 		this.buffer.append(")");//$NON-NLS-1$
1407 		return false;
1408 	}
1409 
1410 	@Override
visit(SingleVariableDeclaration node)1411 	public boolean visit(SingleVariableDeclaration node) {
1412 		printIndent();
1413 		if (node.getAST().apiLevel() == JLS2) {
1414 			printModifiers(node.getModifiers());
1415 		}
1416 		if (node.getAST().apiLevel() >= JLS3) {
1417 			printModifiers(node.modifiers());
1418 		}
1419 		node.getType().accept(this);
1420 		if (node.getAST().apiLevel() >= JLS3) {
1421 			if (node.isVarargs()) {
1422 				if (node.getAST().apiLevel() >= JLS8) {
1423 					List annotations = node.varargsAnnotations();
1424 					if (annotations.size() > 0) {
1425 						this.buffer.append(' ');
1426 					}
1427 					visitAnnotationsList(annotations);
1428 				}
1429 				this.buffer.append("...");//$NON-NLS-1$
1430 			}
1431 		}
1432 		this.buffer.append(" ");//$NON-NLS-1$
1433 		node.getName().accept(this);
1434 		int size = node.getExtraDimensions();
1435 		if (node.getAST().apiLevel() >= JLS8) {
1436 			List dimensions = node.extraDimensions();
1437 			for (int i = 0; i < size; i++) {
1438 				visit((Dimension) dimensions.get(i));
1439 			}
1440 		} else {
1441 			for (int i = 0; i < size; i++) {
1442 				this.buffer.append("[]"); //$NON-NLS-1$
1443 			}
1444 		}
1445 		if (node.getInitializer() != null) {
1446 			this.buffer.append("=");//$NON-NLS-1$
1447 			node.getInitializer().accept(this);
1448 		}
1449 		return false;
1450 	}
1451 
1452 	@Override
visit(StringLiteral node)1453 	public boolean visit(StringLiteral node) {
1454 		this.buffer.append(node.getEscapedValue());
1455 		return false;
1456 	}
1457 
1458 	@Override
visit(SuperConstructorInvocation node)1459 	public boolean visit(SuperConstructorInvocation node) {
1460 		printIndent();
1461 		if (node.getExpression() != null) {
1462 			node.getExpression().accept(this);
1463 			this.buffer.append(".");//$NON-NLS-1$
1464 		}
1465 		if (node.getAST().apiLevel() >= JLS3) {
1466 			if (!node.typeArguments().isEmpty()) {
1467 				this.buffer.append("<");//$NON-NLS-1$
1468 				for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
1469 					Type t = (Type) it.next();
1470 					t.accept(this);
1471 					if (it.hasNext()) {
1472 						this.buffer.append(",");//$NON-NLS-1$
1473 					}
1474 				}
1475 				this.buffer.append(">");//$NON-NLS-1$
1476 			}
1477 		}
1478 		this.buffer.append("super(");//$NON-NLS-1$
1479 		for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
1480 			Expression e = (Expression) it.next();
1481 			e.accept(this);
1482 			if (it.hasNext()) {
1483 				this.buffer.append(",");//$NON-NLS-1$
1484 			}
1485 		}
1486 		this.buffer.append(");\n");//$NON-NLS-1$
1487 		return false;
1488 	}
1489 
1490 	@Override
visit(SuperFieldAccess node)1491 	public boolean visit(SuperFieldAccess node) {
1492 		if (node.getQualifier() != null) {
1493 			node.getQualifier().accept(this);
1494 			this.buffer.append(".");//$NON-NLS-1$
1495 		}
1496 		this.buffer.append("super.");//$NON-NLS-1$
1497 		node.getName().accept(this);
1498 		return false;
1499 	}
1500 
1501 	@Override
visit(SuperMethodInvocation node)1502 	public boolean visit(SuperMethodInvocation node) {
1503 		if (node.getQualifier() != null) {
1504 			node.getQualifier().accept(this);
1505 			this.buffer.append(".");//$NON-NLS-1$
1506 		}
1507 		this.buffer.append("super.");//$NON-NLS-1$
1508 		if (node.getAST().apiLevel() >= JLS3) {
1509 			if (!node.typeArguments().isEmpty()) {
1510 				this.buffer.append("<");//$NON-NLS-1$
1511 				for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) {
1512 					Type t = (Type) it.next();
1513 					t.accept(this);
1514 					if (it.hasNext()) {
1515 						this.buffer.append(",");//$NON-NLS-1$
1516 					}
1517 				}
1518 				this.buffer.append(">");//$NON-NLS-1$
1519 			}
1520 		}
1521 		node.getName().accept(this);
1522 		this.buffer.append("(");//$NON-NLS-1$
1523 		for (Iterator it = node.arguments().iterator(); it.hasNext(); ) {
1524 			Expression e = (Expression) it.next();
1525 			e.accept(this);
1526 			if (it.hasNext()) {
1527 				this.buffer.append(",");//$NON-NLS-1$
1528 			}
1529 		}
1530 		this.buffer.append(")");//$NON-NLS-1$
1531 		return false;
1532 	}
1533 
1534 	/*
1535 	 * @see ASTVisitor#visit(SuperMethodReference)
1536 	 *
1537 	 * @since 3.10
1538 	 */
1539 	@Override
visit(SuperMethodReference node)1540 	public boolean visit(SuperMethodReference node) {
1541 		if (node.getQualifier() != null) {
1542 			node.getQualifier().accept(this);
1543 			this.buffer.append('.');
1544 		}
1545 		this.buffer.append("super");//$NON-NLS-1$
1546 		visitReferenceTypeArguments(node.typeArguments());
1547 		node.getName().accept(this);
1548 		return false;
1549 	}
1550 
1551 	@Override
visit(SwitchCase node)1552 	public boolean visit(SwitchCase node) {
1553 		if ((node.getAST().apiLevel() >= AST.JLS14)) {
1554 			if (node.isDefault()) {
1555 				this.buffer.append("default");//$NON-NLS-1$
1556 				this.buffer.append(node.isSwitchLabeledRule() ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$
1557 			} else {
1558 				this.buffer.append("case ");//$NON-NLS-1$
1559 				for (Iterator it = node.expressions().iterator(); it.hasNext(); ) {
1560 					Expression t = (Expression) it.next();
1561 						t.accept(this);
1562 						this.buffer.append(it.hasNext() ? ", " : //$NON-NLS-1$
1563 							node.isSwitchLabeledRule() ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$
1564 				}
1565 			}
1566 		}
1567 		else {
1568 			if (node.isDefault()) {
1569 				this.buffer.append("default :\n");//$NON-NLS-1$
1570 			} else {
1571 				this.buffer.append("case ");//$NON-NLS-1$
1572 				getSwitchExpression(node).accept(this);
1573 				this.buffer.append(":\n");//$NON-NLS-1$
1574 			}
1575 		}
1576 		this.indent++; //decremented in visit(SwitchStatement)
1577 		return false;
1578 	}
1579 	/**
1580 	 * @deprecated
1581 	 */
getSwitchExpression(SwitchCase node)1582 	private Expression getSwitchExpression(SwitchCase node) {
1583 		return node.getExpression();
1584 	}
1585 
visitSwitchNode(ASTNode node)1586 	private void visitSwitchNode(ASTNode node) {
1587 		this.buffer.append("switch (");//$NON-NLS-1$
1588 		if (node instanceof SwitchExpression) {
1589 			((SwitchExpression)node).getExpression().accept(this);
1590 		} else if (node instanceof SwitchStatement) {
1591 			((SwitchStatement)node).getExpression().accept(this);
1592 		}
1593 		this.buffer.append(") ");//$NON-NLS-1$
1594 		this.buffer.append("{\n");//$NON-NLS-1$
1595 		this.indent++;
1596 		if (node instanceof SwitchExpression) {
1597 			for (Iterator it = ((SwitchExpression)node).statements().iterator(); it.hasNext(); ) {
1598 				Statement s = (Statement) it.next();
1599 				s.accept(this);
1600 				this.indent--; // incremented in visit(SwitchCase)
1601 			}
1602 		} else if (node instanceof SwitchStatement) {
1603 			for (Iterator it = ((SwitchStatement)node).statements().iterator(); it.hasNext(); ) {
1604 				Statement s = (Statement) it.next();
1605 				s.accept(this);
1606 				this.indent--; // incremented in visit(SwitchCase)
1607 			}
1608 		}
1609 		this.indent--;
1610 		printIndent();
1611 		this.buffer.append("}\n");//$NON-NLS-1$
1612 
1613 	}
1614 	@Override
visit(SwitchExpression node)1615 	public boolean visit(SwitchExpression node) {
1616 		visitSwitchNode(node);
1617 		return false;
1618 	}
1619 
1620 	@Override
visit(SwitchStatement node)1621 	public boolean visit(SwitchStatement node) {
1622 		visitSwitchNode(node);
1623 		return false;
1624 	}
1625 
1626 	@Override
visit(SynchronizedStatement node)1627 	public boolean visit(SynchronizedStatement node) {
1628 		this.buffer.append("synchronized (");//$NON-NLS-1$
1629 		node.getExpression().accept(this);
1630 		this.buffer.append(") ");//$NON-NLS-1$
1631 		node.getBody().accept(this);
1632 		return false;
1633 	}
1634 
1635 	@Override
visit(TagElement node)1636 	public boolean visit(TagElement node) {
1637 		if (node.isNested()) {
1638 			// nested tags are always enclosed in braces
1639 			this.buffer.append("{");//$NON-NLS-1$
1640 		} else {
1641 			// top-level tags always begin on a new line
1642 			this.buffer.append("\n * ");//$NON-NLS-1$
1643 		}
1644 		boolean previousRequiresWhiteSpace = false;
1645 		if (node.getTagName() != null) {
1646 			this.buffer.append(node.getTagName());
1647 			previousRequiresWhiteSpace = true;
1648 		}
1649 		boolean previousRequiresNewLine = false;
1650 		for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
1651 			ASTNode e = (ASTNode) it.next();
1652 			// Name, MemberRef, MethodRef, and nested TagElement do not include white space.
1653 			// TextElements don't always include whitespace, see <https://bugs.eclipse.org/206518>.
1654 			boolean currentIncludesWhiteSpace = false;
1655 			if (e instanceof TextElement) {
1656 				String text = ((TextElement) e).getText();
1657 				if (text.length() > 0 && ScannerHelper.isWhitespace(text.charAt(0))) {
1658 					currentIncludesWhiteSpace = true; // workaround for https://bugs.eclipse.org/403735
1659 				}
1660 			}
1661 			if (previousRequiresNewLine && currentIncludesWhiteSpace) {
1662 				this.buffer.append("\n * ");//$NON-NLS-1$
1663 			}
1664 			previousRequiresNewLine = currentIncludesWhiteSpace;
1665 			// add space if required to separate
1666 			if (previousRequiresWhiteSpace && !currentIncludesWhiteSpace) {
1667 				this.buffer.append(" "); //$NON-NLS-1$
1668 			}
1669 			e.accept(this);
1670 			previousRequiresWhiteSpace = !currentIncludesWhiteSpace && !(e instanceof TagElement);
1671 		}
1672 		if (node.isNested()) {
1673 			this.buffer.append("}");//$NON-NLS-1$
1674 		}
1675 		return false;
1676 	}
1677 
1678 	@Override
visit(TextBlock node)1679 	public boolean visit(TextBlock node) {
1680 		this.buffer.append(node.getEscapedValue());
1681 		return false;
1682 	}
1683 
1684 	@Override
visit(TextElement node)1685 	public boolean visit(TextElement node) {
1686 		this.buffer.append(node.getText());
1687 		return false;
1688 	}
1689 
1690 	@Override
visit(ThisExpression node)1691 	public boolean visit(ThisExpression node) {
1692 		if (node.getQualifier() != null) {
1693 			node.getQualifier().accept(this);
1694 			this.buffer.append(".");//$NON-NLS-1$
1695 		}
1696 		this.buffer.append("this");//$NON-NLS-1$
1697 		return false;
1698 	}
1699 
1700 	@Override
visit(ThrowStatement node)1701 	public boolean visit(ThrowStatement node) {
1702 		printIndent();
1703 		this.buffer.append("throw ");//$NON-NLS-1$
1704 		node.getExpression().accept(this);
1705 		this.buffer.append(";\n");//$NON-NLS-1$
1706 		return false;
1707 	}
1708 
1709 	@Override
visit(TryStatement node)1710 	public boolean visit(TryStatement node) {
1711 		printIndent();
1712 		this.buffer.append("try ");//$NON-NLS-1$
1713 		if (node.getAST().apiLevel() >= JLS4) {
1714 			List resources = node.resources();
1715 			if (!resources.isEmpty()) {
1716 				this.buffer.append('(');
1717 				for (Iterator it = resources.iterator(); it.hasNext(); ) {
1718 					Expression variable = (Expression) it.next();
1719 					variable.accept(this);
1720 					if (it.hasNext()) {
1721 						this.buffer.append(';');
1722 					}
1723 				}
1724 				this.buffer.append(')');
1725 			}
1726 		}
1727 		node.getBody().accept(this);
1728 		this.buffer.append(" ");//$NON-NLS-1$
1729 		for (Iterator it = node.catchClauses().iterator(); it.hasNext(); ) {
1730 			CatchClause cc = (CatchClause) it.next();
1731 			cc.accept(this);
1732 		}
1733 		if (node.getFinally() != null) {
1734 			this.buffer.append(" finally ");//$NON-NLS-1$
1735 			node.getFinally().accept(this);
1736 		}
1737 		return false;
1738 	}
1739 
1740 	@Override
visit(TypeDeclaration node)1741 	public boolean visit(TypeDeclaration node) {
1742 		if (node.getJavadoc() != null) {
1743 			node.getJavadoc().accept(this);
1744 		}
1745 		if (node.getAST().apiLevel() == JLS2) {
1746 			printModifiers(node.getModifiers());
1747 		}
1748 		if (node.getAST().apiLevel() >= JLS3) {
1749 			printModifiers(node.modifiers());
1750 		}
1751 		this.buffer.append(node.isInterface() ? "interface " : "class ");//$NON-NLS-2$//$NON-NLS-1$
1752 		node.getName().accept(this);
1753 		if (node.getAST().apiLevel() >= JLS3) {
1754 			if (!node.typeParameters().isEmpty()) {
1755 				this.buffer.append("<");//$NON-NLS-1$
1756 				for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) {
1757 					TypeParameter t = (TypeParameter) it.next();
1758 					t.accept(this);
1759 					if (it.hasNext()) {
1760 						this.buffer.append(",");//$NON-NLS-1$
1761 					}
1762 				}
1763 				this.buffer.append(">");//$NON-NLS-1$
1764 			}
1765 		}
1766 		this.buffer.append(" ");//$NON-NLS-1$
1767 		if (node.getAST().apiLevel() == JLS2) {
1768 			if (getSuperclass(node) != null) {
1769 				this.buffer.append("extends ");//$NON-NLS-1$
1770 				getSuperclass(node).accept(this);
1771 				this.buffer.append(" ");//$NON-NLS-1$
1772 			}
1773 			if (!superInterfaces(node).isEmpty()) {
1774 				this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$
1775 				for (Iterator it = superInterfaces(node).iterator(); it.hasNext(); ) {
1776 					Name n = (Name) it.next();
1777 					n.accept(this);
1778 					if (it.hasNext()) {
1779 						this.buffer.append(", ");//$NON-NLS-1$
1780 					}
1781 				}
1782 				this.buffer.append(" ");//$NON-NLS-1$
1783 			}
1784 		}
1785 		if (node.getAST().apiLevel() >= JLS3) {
1786 			if (node.getSuperclassType() != null) {
1787 				this.buffer.append("extends ");//$NON-NLS-1$
1788 				node.getSuperclassType().accept(this);
1789 				this.buffer.append(" ");//$NON-NLS-1$
1790 			}
1791 			if (!node.superInterfaceTypes().isEmpty()) {
1792 				this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$
1793 				for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) {
1794 					Type t = (Type) it.next();
1795 					t.accept(this);
1796 					if (it.hasNext()) {
1797 						this.buffer.append(", ");//$NON-NLS-1$
1798 					}
1799 				}
1800 				this.buffer.append(" ");//$NON-NLS-1$
1801 			}
1802 		}
1803 		this.buffer.append("{\n");//$NON-NLS-1$
1804 		this.indent++;
1805 		for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
1806 			BodyDeclaration d = (BodyDeclaration) it.next();
1807 			d.accept(this);
1808 		}
1809 		this.indent--;
1810 		printIndent();
1811 		this.buffer.append("}\n");//$NON-NLS-1$
1812 		return false;
1813 	}
1814 
1815 	@Override
visit(TypeDeclarationStatement node)1816 	public boolean visit(TypeDeclarationStatement node) {
1817 		if (node.getAST().apiLevel() == JLS2) {
1818 			getTypeDeclaration(node).accept(this);
1819 		}
1820 		if (node.getAST().apiLevel() >= JLS3) {
1821 			node.getDeclaration().accept(this);
1822 		}
1823 		return false;
1824 	}
1825 
1826 	@Override
visit(TypeLiteral node)1827 	public boolean visit(TypeLiteral node) {
1828 		node.getType().accept(this);
1829 		this.buffer.append(".class");//$NON-NLS-1$
1830 		return false;
1831 	}
1832 
1833 	/*
1834 	 * @see ASTVisitor#visit(TypeMethodReference)
1835 	 *
1836 	 * @since 3.10
1837 	 */
1838 	@Override
visit(TypeMethodReference node)1839 	public boolean visit(TypeMethodReference node) {
1840 		node.getType().accept(this);
1841 		visitReferenceTypeArguments(node.typeArguments());
1842 		node.getName().accept(this);
1843 		return false;
1844 	}
1845 
1846 	@Override
visit(TypeParameter node)1847 	public boolean visit(TypeParameter node) {
1848 		if (node.getAST().apiLevel() >= JLS8) {
1849 			printModifiers(node.modifiers());
1850 		}
1851 		node.getName().accept(this);
1852 		if (!node.typeBounds().isEmpty()) {
1853 			this.buffer.append(" extends ");//$NON-NLS-1$
1854 			for (Iterator it = node.typeBounds().iterator(); it.hasNext(); ) {
1855 				Type t = (Type) it.next();
1856 				t.accept(this);
1857 				if (it.hasNext()) {
1858 					this.buffer.append(" & ");//$NON-NLS-1$
1859 				}
1860 			}
1861 		}
1862 		return false;
1863 	}
1864 
1865 	@Override
visit(UnionType node)1866 	public boolean visit(UnionType node) {
1867 		for (Iterator it = node.types().iterator(); it.hasNext(); ) {
1868 			Type t = (Type) it.next();
1869 			t.accept(this);
1870 			if (it.hasNext()) {
1871 				this.buffer.append('|');
1872 			}
1873 		}
1874 		return false;
1875 	}
1876 
1877 	@Override
visit(UsesDirective node)1878 	public boolean visit(UsesDirective node) {
1879 		printIndent();
1880 		this.buffer.append("uses");//$NON-NLS-1$
1881 		this.buffer.append(" ");//$NON-NLS-1$
1882 		node.getName().accept(this);
1883 		this.buffer.append(";\n");//$NON-NLS-1$
1884 		return false;
1885 	}
1886 
1887 	@Override
visit(VariableDeclarationExpression node)1888 	public boolean visit(VariableDeclarationExpression node) {
1889 		if (node.getAST().apiLevel() == JLS2) {
1890 			printModifiers(node.getModifiers());
1891 		}
1892 		if (node.getAST().apiLevel() >= JLS3) {
1893 			printModifiers(node.modifiers());
1894 		}
1895 		node.getType().accept(this);
1896 		this.buffer.append(" ");//$NON-NLS-1$
1897 		for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
1898 			VariableDeclarationFragment f = (VariableDeclarationFragment) it.next();
1899 			f.accept(this);
1900 			if (it.hasNext()) {
1901 				this.buffer.append(", ");//$NON-NLS-1$
1902 			}
1903 		}
1904 		return false;
1905 	}
1906 
1907 	@Override
visit(VariableDeclarationFragment node)1908 	public boolean visit(VariableDeclarationFragment node) {
1909 		node.getName().accept(this);
1910 		int size = node.getExtraDimensions();
1911 		if (node.getAST().apiLevel() >= JLS8) {
1912 			List dimensions = node.extraDimensions();
1913 			for (int i = 0; i < size; i++) {
1914 				visit((Dimension) dimensions.get(i));
1915 			}
1916 		} else {
1917 			for (int i = 0; i < size; i++) {
1918 				this.buffer.append("[]");//$NON-NLS-1$
1919 			}
1920 		}
1921 		if (node.getInitializer() != null) {
1922 			this.buffer.append("=");//$NON-NLS-1$
1923 			node.getInitializer().accept(this);
1924 		}
1925 		return false;
1926 	}
1927 
1928 	@Override
visit(VariableDeclarationStatement node)1929 	public boolean visit(VariableDeclarationStatement node) {
1930 		printIndent();
1931 		if (node.getAST().apiLevel() == JLS2) {
1932 			printModifiers(node.getModifiers());
1933 		}
1934 		if (node.getAST().apiLevel() >= JLS3) {
1935 			printModifiers(node.modifiers());
1936 		}
1937 		node.getType().accept(this);
1938 		this.buffer.append(" ");//$NON-NLS-1$
1939 		for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
1940 			VariableDeclarationFragment f = (VariableDeclarationFragment) it.next();
1941 			f.accept(this);
1942 			if (it.hasNext()) {
1943 				this.buffer.append(", ");//$NON-NLS-1$
1944 			}
1945 		}
1946 		this.buffer.append(";\n");//$NON-NLS-1$
1947 		return false;
1948 	}
1949 
1950 	@Override
visit(WhileStatement node)1951 	public boolean visit(WhileStatement node) {
1952 		printIndent();
1953 		this.buffer.append("while (");//$NON-NLS-1$
1954 		node.getExpression().accept(this);
1955 		this.buffer.append(") ");//$NON-NLS-1$
1956 		node.getBody().accept(this);
1957 		return false;
1958 	}
1959 
1960 	@Override
visit(WildcardType node)1961 	public boolean visit(WildcardType node) {
1962 		visitTypeAnnotations(node);
1963 		this.buffer.append("?");//$NON-NLS-1$
1964 		Type bound = node.getBound();
1965 		if (bound != null) {
1966 			if (node.isUpperBound()) {
1967 				this.buffer.append(" extends ");//$NON-NLS-1$
1968 			} else {
1969 				this.buffer.append(" super ");//$NON-NLS-1$
1970 			}
1971 			bound.accept(this);
1972 		}
1973 		return false;
1974 	}
1975 
1976 	@Override
visit(YieldStatement node)1977 	public boolean visit(YieldStatement node) {
1978 		if ((node.getAST().apiLevel() >= AST.JLS14) && node.isImplicit()  && node.getExpression() == null) {
1979 			return false;
1980 		}
1981 		printIndent();
1982 		this.buffer.append("yield"); //$NON-NLS-1$
1983 		if (node.getExpression() != null) {
1984 			this.buffer.append(" ");//$NON-NLS-1$
1985 			node.getExpression().accept(this);
1986 		}
1987 		this.buffer.append(";\n");//$NON-NLS-1$
1988 		return false;
1989 	}
1990 
1991 	/**
1992 	 * @deprecated
1993 	 */
visitComponentType(ArrayType node)1994 	private void visitComponentType(ArrayType node) {
1995 		node.getComponentType().accept(this);
1996 	}
1997 
1998 }
1999