View Javadoc

1   /*
2    * Spoon - http://spoon.gforge.inria.fr/
3    * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
4    *
5    * This software is governed by the CeCILL-C License under French law and
6    * abiding by the rules of distribution of free software. You can use, modify
7    * and/or redistribute the software under the terms of the CeCILL-C license as
8    * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
9    *
10   * This program is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
13   *
14   * The fact that you are presently reading this means that you have had
15   * knowledge of the CeCILL-C license and that you accept its terms.
16   */
17  
18  package spoon.reflect.visitor;
19  
20  import java.lang.annotation.Annotation;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Stack;
27  import java.util.TreeMap;
28  import java.util.Map.Entry;
29  
30  import spoon.processing.Environment;
31  import spoon.reflect.code.BinaryOperatorKind;
32  import spoon.reflect.code.CtArrayAccess;
33  import spoon.reflect.code.CtAssert;
34  import spoon.reflect.code.CtAssignment;
35  import spoon.reflect.code.CtBinaryOperator;
36  import spoon.reflect.code.CtBlock;
37  import spoon.reflect.code.CtBreak;
38  import spoon.reflect.code.CtCase;
39  import spoon.reflect.code.CtCatch;
40  import spoon.reflect.code.CtCodeElement;
41  import spoon.reflect.code.CtCodeSnippetExpression;
42  import spoon.reflect.code.CtCodeSnippetStatement;
43  import spoon.reflect.code.CtConditional;
44  import spoon.reflect.code.CtContinue;
45  import spoon.reflect.code.CtDo;
46  import spoon.reflect.code.CtExpression;
47  import spoon.reflect.code.CtFieldAccess;
48  import spoon.reflect.code.CtFor;
49  import spoon.reflect.code.CtForEach;
50  import spoon.reflect.code.CtIf;
51  import spoon.reflect.code.CtInvocation;
52  import spoon.reflect.code.CtLiteral;
53  import spoon.reflect.code.CtLocalVariable;
54  import spoon.reflect.code.CtNewArray;
55  import spoon.reflect.code.CtNewClass;
56  import spoon.reflect.code.CtOperatorAssignment;
57  import spoon.reflect.code.CtReturn;
58  import spoon.reflect.code.CtStatement;
59  import spoon.reflect.code.CtStatementList;
60  import spoon.reflect.code.CtSwitch;
61  import spoon.reflect.code.CtSynchronized;
62  import spoon.reflect.code.CtTargetedExpression;
63  import spoon.reflect.code.CtThrow;
64  import spoon.reflect.code.CtTry;
65  import spoon.reflect.code.CtUnaryOperator;
66  import spoon.reflect.code.CtVariableAccess;
67  import spoon.reflect.code.CtWhile;
68  import spoon.reflect.code.UnaryOperatorKind;
69  import spoon.reflect.cu.CompilationUnit;
70  import spoon.reflect.cu.Import;
71  import spoon.reflect.declaration.CtAnnotation;
72  import spoon.reflect.declaration.CtAnnotationType;
73  import spoon.reflect.declaration.CtAnonymousExecutable;
74  import spoon.reflect.declaration.CtClass;
75  import spoon.reflect.declaration.CtConstructor;
76  import spoon.reflect.declaration.CtElement;
77  import spoon.reflect.declaration.CtEnum;
78  import spoon.reflect.declaration.CtExecutable;
79  import spoon.reflect.declaration.CtField;
80  import spoon.reflect.declaration.CtInterface;
81  import spoon.reflect.declaration.CtMethod;
82  import spoon.reflect.declaration.CtModifiable;
83  import spoon.reflect.declaration.CtNamedElement;
84  import spoon.reflect.declaration.CtPackage;
85  import spoon.reflect.declaration.CtParameter;
86  import spoon.reflect.declaration.CtSimpleType;
87  import spoon.reflect.declaration.CtType;
88  import spoon.reflect.declaration.CtTypeParameter;
89  import spoon.reflect.declaration.ModifierKind;
90  import spoon.reflect.reference.CtArrayTypeReference;
91  import spoon.reflect.reference.CtExecutableReference;
92  import spoon.reflect.reference.CtFieldReference;
93  import spoon.reflect.reference.CtLocalVariableReference;
94  import spoon.reflect.reference.CtPackageReference;
95  import spoon.reflect.reference.CtParameterReference;
96  import spoon.reflect.reference.CtReference;
97  import spoon.reflect.reference.CtTypeParameterReference;
98  import spoon.reflect.reference.CtTypeReference;
99  import spoon.support.reflect.cu.CtLineElementComparator;
100 import spoon.support.util.SortedList;
101 
102 /**
103  * A visitor for generating Java code from the program compile-time metamodel.
104  */
105 public class DefaultJavaPrettyPrinter implements CtVisitor, PrettyPrinter {
106 
107 	/**
108 	 * Java file extension (.java).
109 	 */
110 	public static final String JAVA_FILE_EXTENSION = ".java";
111 
112 	/**
113 	 * Package declaration file name.
114 	 */
115 	public static final String JAVA_PACKAGE_DECLARATION = "package-info"
116 			+ JAVA_FILE_EXTENSION;
117 
118 	Map<Integer, Integer> lineNumberMapping = new HashMap<Integer, Integer>();
119 
120 	/**
121 	 * A scanner that calculates the imports for a given model.
122 	 */
123 	private class ImportScanner extends CtScanner {
124 		@SuppressWarnings("unchecked")
125 		Map<String, CtTypeReference<?>> imports = new TreeMap<String, CtTypeReference<?>>();
126 
127 		/**
128 		 * Adds a type to the imports.
129 		 */
130 		public <T> boolean addImport(CtTypeReference<T> ref) {
131 			if (imports.containsKey(ref.getSimpleName())) {
132 				return isImported(ref);
133 			}
134 			imports.put(ref.getSimpleName(), ref);
135 			return true;
136 		}
137 
138 		/**
139 		 * Calculates needed imports for the given field access.
140 		 */
141 		@Override
142 		public <T> void visitCtFieldAccess(CtFieldAccess<T> fieldAccess) {
143 			enter(fieldAccess);
144 			scan(fieldAccess.getVariable());
145 			// scan(fieldAccess.getType());
146 			scan(fieldAccess.getAnnotations());
147 			scanReferences(fieldAccess.getTypeCasts());
148 			scan(fieldAccess.getVariable());
149 			scan(fieldAccess.getTarget());
150 			exit(fieldAccess);
151 		}
152 
153 		@Override
154 		public <T> void visitCtFieldReference(CtFieldReference<T> reference) {
155 			enterReference(reference);
156 			scan(reference.getDeclaringType());
157 			// scan(reference.getType());
158 			exitReference(reference);
159 		}
160 
161 		public <T> boolean isImported(CtTypeReference<T> ref) {
162 			if (imports.containsKey(ref.getSimpleName())) {
163 				CtTypeReference<?> exist = imports.get(ref.getSimpleName());
164 				if (exist.getQualifiedName().equals(ref.getQualifiedName())) {
165 					return true;
166 				}
167 			}
168 			return false;
169 		}
170 
171 		@Override
172 		public <T> void visitCtExecutableReference(
173 				CtExecutableReference<T> reference) {
174 			enterReference(reference);
175 			scanReferences(reference.getParameterTypes());
176 			scanReferences(reference.getActualTypeArguments());
177 			exitReference(reference);
178 		}
179 
180 		@Override
181 		public <T> void visitCtTypeReference(CtTypeReference<T> reference) {
182 			if (!(reference instanceof CtArrayTypeReference)) {
183 				if (reference.getDeclaringType() == null) {
184 					addImport(reference);
185 				} else {
186 					addImport(reference.getDeclaringType());
187 				}
188 			}
189 			super.visitCtTypeReference(reference);
190 
191 		}
192 
193 		@Override
194 		public <A extends Annotation> void visitCtAnnotationType(
195 				CtAnnotationType<A> annotationType) {
196 			addImport(annotationType.getReference());
197 			super.visitCtAnnotationType(annotationType);
198 		}
199 
200 		@Override
201 		public <T extends Enum<?>> void visitCtEnum(CtEnum<T> ctEnum) {
202 			addImport(ctEnum.getReference());
203 			super.visitCtEnum(ctEnum);
204 		}
205 
206 		@Override
207 		public <T> void visitCtInterface(CtInterface<T> intrface) {
208 			addImport(intrface.getReference());
209 			for (CtSimpleType<?> t : intrface.getNestedTypes()) {
210 				addImport(t.getReference());
211 			}
212 			super.visitCtInterface(intrface);
213 		}
214 
215 		@Override
216 		public <T> void visitCtClass(CtClass<T> ctClass) {
217 			addImport(ctClass.getReference());
218 			for (CtSimpleType<?> t : ctClass.getNestedTypes()) {
219 				addImport(t.getReference());
220 			}
221 			super.visitCtClass(ctClass);
222 		}
223 	}
224 
225 	private class Printingcontext {
226 		boolean noTypeDecl = false;
227 
228 		Stack<CtTypeReference<?>> currentThis = new Stack<CtTypeReference<?>>();
229 
230 		CtSimpleType<?> currentTopLevel;
231 
232 		boolean ignoreGenerics = false;
233 
234 		boolean ignoreImport = false;
235 
236 		/** Layout variables */
237 		int jumped = 0;
238 
239 		int lineLength = 80;
240 
241 		int lineLengthMargin = 5;
242 
243 		int nbTabs = 0;
244 
245 		Stack<CtExpression<?>> parenthesedExpression = new Stack<CtExpression<?>>();
246 
247 		boolean printDocs = true;
248 
249 		boolean printShortName = false;
250 
251 		boolean skipArray = false;
252 
253 		int target = 0;
254 
255 		void enterTarget() {
256 			target++;
257 		}
258 
259 		void exitTarget() {
260 			if (jumped > 0) {
261 				jumped--;
262 			} else {
263 				target--;
264 			}
265 		}
266 
267 		void jumpTarget() {
268 			jumped++;
269 			target--;
270 		}
271 
272 	}
273 
274 	/**
275 	 * The tabulation string.
276 	 */
277 	// public static final String TAB = " ";
278 	/**
279 	 * The printing context.
280 	 */
281 	public Printingcontext context = new Printingcontext();
282 
283 	private ImportScanner importsContext = new ImportScanner();
284 
285 	/**
286 	 * The string buffer in which the code is generated.
287 	 */
288 	private StringBuffer sbf = new StringBuffer();
289 
290 	Environment env;
291 
292 	/**
293 	 * Creates a new code generator visitor.
294 	 */
295 	public DefaultJavaPrettyPrinter(Environment env) {
296 		this.env = env;
297 	}
298 
299 	/**
300 	 * Decrements the current number of tabs.
301 	 */
302 	public DefaultJavaPrettyPrinter decTab() {
303 		context.nbTabs--;
304 		return this;
305 	}
306 
307 	private void undefLine(int line) {
308 		if (lineNumberMapping.get(line) == null) {
309 			// overload mapping (undefined line)
310 			lineNumberMapping.put(line, 0);
311 		}
312 	}
313 
314 	private void mapLine(int line, CtElement e) {
315 		if ((e.getPosition() != null)
316 				&& (e.getPosition().getCompilationUnit() == sourceCompilationUnit)) {
317 			// only map elements comming from the source CU
318 			lineNumberMapping.put(line, e.getPosition().getLine());
319 		} else {
320 			undefLine(line);
321 		}
322 	}
323 
324 	/**
325 	 * Enters an expression.
326 	 */
327 	protected void enterCtExpression(CtExpression<?> e) {
328 		mapLine(line, e);
329 		if (shouldSetBracket(e)) {
330 			context.parenthesedExpression.push(e);
331 			write("(");
332 		}
333 		if (!e.getTypeCasts().isEmpty()) {
334 			for (CtTypeReference<?> r : e.getTypeCasts()) {
335 				write("(");
336 				DefaultJavaPrettyPrinter.this.scan(r);
337 				write(")");
338 				write("(");
339 				context.parenthesedExpression.push(e);
340 			}
341 		}
342 	}
343 
344 	/**
345 	 * Enters a statement.
346 	 */
347 	protected void enterCtStatement(CtStatement s) {
348 		mapLine(line, s);
349 		writeAnnotations(s);
350 		if (s.getLabel() != null) {
351 			write(s.getLabel()).write(" : ");
352 		}
353 	}
354 
355 	/**
356 	 * Exits an expression.
357 	 */
358 	protected void exitCtExpression(CtExpression<?> e) {
359 		while ((context.parenthesedExpression.size() > 0)
360 				&& e.equals(context.parenthesedExpression.peek())) {
361 			context.parenthesedExpression.pop();
362 			write(")");
363 		}
364 	}
365 
366 	/**
367 	 * Gets the imports.
368 	 */
369 	public Collection<CtTypeReference<?>> getImports() {
370 		return importsContext.imports.values();
371 	}
372 
373 	/*
374 	 * (non-Javadoc)
375 	 *
376 	 * @see spoon.reflect.visitor.JavaPrettyPrinter#getPackageDeclaration()
377 	 */
378 	public String getPackageDeclaration() {
379 		StringBuffer bck = sbf;
380 		sbf = new StringBuffer();
381 		Map<String, CtTypeReference<?>> tmp = importsContext.imports;
382 		importsContext.imports = new TreeMap<String, CtTypeReference<?>>();
383 
384 		for (CtAnnotation<?> a : context.currentTopLevel.getPackage()
385 				.getAnnotations()) {
386 			a.accept(this);
387 		}
388 
389 		if (!context.currentTopLevel.getPackage().getQualifiedName().equals(
390 				CtPackage.TOP_LEVEL_PACKAGE_NAME)) {
391 			write("package "
392 					+ context.currentTopLevel.getPackage().getQualifiedName()
393 					+ ";");
394 		}
395 		String ret = sbf.toString();
396 		sbf = bck;
397 
398 		importsContext.imports = tmp;
399 		return ret;
400 	}
401 
402 	/*
403 	 * (non-Javadoc)
404 	 *
405 	 * @see spoon.reflect.visitor.JavaPrettyPrinter#getResult()
406 	 */
407 	public StringBuffer getResult() {
408 		return sbf;
409 	}
410 
411 	/**
412 	 * Increments the current number of tabs.
413 	 */
414 	public DefaultJavaPrettyPrinter incTab() {
415 		context.nbTabs++;
416 		return this;
417 	}
418 
419 	/**
420 	 * Sets the current number of tabs.
421 	 */
422 	public DefaultJavaPrettyPrinter setTabCount(int tabCount) {
423 		context.nbTabs = tabCount;
424 		return this;
425 	}
426 
427 	private boolean isHiddenByField(CtType<?> container, CtTypeReference<?> type) {
428 		if (container == null) {
429 			return false;
430 		}
431 		// TODO: Deal with anonymous class better
432 		if ((container.getSimpleName() == null)
433 				|| container.getSimpleName().equals("")) {
434 			return false;
435 		}
436 		for (CtFieldReference<?> f : container.getReference().getAllFields()) {
437 			if (f.getSimpleName().equals(type.getSimpleName())) {
438 				return true;
439 			}
440 		}
441 		return false;
442 	}
443 
444 	private boolean isWhite(char c) {
445 		return (c == ' ') || (c == '\t') || (c == '\n');
446 	}
447 
448 	/**
449 	 * Make the imports for a given type.
450 	 */
451 	public void makeImports(CtSimpleType<?> type) {
452 		context.currentTopLevel = type;
453 		importsContext.addImport(context.currentTopLevel.getReference());
454 		importsContext.scan(context.currentTopLevel);
455 	}
456 
457 	/**
458 	 * Write a post unary operator.
459 	 */
460 	protected void postWriteUnaryOperator(UnaryOperatorKind o) {
461 		switch (o) {
462 		case POSTINC:
463 			write("++");
464 			break;
465 		case POSTDEC:
466 			write("--");
467 			break;
468 		}
469 	}
470 
471 	/**
472 	 * Write a pre unary operator.
473 	 */
474 	void preWriteUnaryOperator(UnaryOperatorKind o) {
475 		switch (o) {
476 		case POS:
477 			write("+");
478 			break;
479 		case NEG:
480 			write("-");
481 			break;
482 		case NOT:
483 			write("!");
484 			break;
485 		case COMPL:
486 			write("~");
487 			break;
488 		case PREINC:
489 			write("++");
490 			break;
491 		case PREDEC:
492 			write("--");
493 			break;
494 		}
495 	}
496 
497 	/**
498 	 * Removes the last non-white charater.
499 	 */
500 	protected DefaultJavaPrettyPrinter removeLastChar() {
501 		while (isWhite(sbf.charAt(sbf.length() - 1))) {
502 			sbf.deleteCharAt(sbf.length() - 1);
503 		}
504 		sbf.deleteCharAt(sbf.length() - 1);
505 		while (isWhite(sbf.charAt(sbf.length() - 1))) {
506 			sbf.deleteCharAt(sbf.length() - 1);
507 		}
508 		return this;
509 	}
510 
511 	/**
512 	 * The generic scan method for an element.
513 	 */
514 	public DefaultJavaPrettyPrinter scan(CtElement e) {
515 		if (e != null) {
516 			e.accept(this);
517 		}
518 		return this;
519 	}
520 
521 	/**
522 	 * The generic scan method for a reference.
523 	 */
524 	public DefaultJavaPrettyPrinter scan(CtReference ref) {
525 		if (ref != null) {
526 			ref.accept(this);
527 		}
528 		return this;
529 	}
530 
531 	private boolean shouldSetBracket(CtExpression<?> e) {
532 		if (e.getTypeCasts().size() != 0) {
533 			return true;
534 		}
535 		if ((e.getParent() instanceof CtBinaryOperator)
536 				|| (e.getParent() instanceof CtUnaryOperator)) {
537 			return (e instanceof CtTargetedExpression)
538 					|| (e instanceof CtAssignment)
539 					|| (e instanceof CtConditional)
540 					|| (e instanceof CtUnaryOperator);
541 		}
542 		if (e.getParent() instanceof CtTargetedExpression) {
543 			return (e instanceof CtBinaryOperator)
544 					|| (e instanceof CtAssignment)
545 					|| (e instanceof CtConditional);
546 		}
547 
548 		return false;
549 	}
550 
551 	/**
552 	 * Gets the currently pretty-printed string.
553 	 */
554 	@Override
555 	public String toString() {
556 		return sbf.toString();
557 	}
558 
559 	public <A extends Annotation> void visitCtAnnotation(
560 			CtAnnotation<A> annotation) {
561 		writeAnnotations(annotation);
562 		write("@");
563 		scan(annotation.getAnnotationType());
564 		if (annotation.getElementValues().size() > 0) {
565 			write("(");
566 			for (Entry<String, Object> e : annotation.getElementValues()
567 					.entrySet()) {
568 				write(e.getKey() + " = ");
569 				writeAnnotationElement(e.getValue());
570 				write(", ");
571 			}
572 			removeLastChar();
573 			write(")");
574 		}
575 		writeln();
576 	}
577 
578 	public <A extends Annotation> void visitCtAnnotationType(
579 			CtAnnotationType<A> annotationType) {
580 		visitCtSimpleType(annotationType);
581 		write("@interface " + annotationType.getSimpleName() + " {").incTab();
582 
583 		SortedList<CtElement> lst = new SortedList<CtElement>(
584 				new CtLineElementComparator());
585 
586 		lst.addAll(annotationType.getNestedTypes());
587 		lst.addAll(annotationType.getFields());
588 
589 		for (CtElement el : lst) {
590 			writeln().scan(el).writeln();
591 		}
592 		decTab().writeln().write("}");
593 	}
594 
595 	public void visitCtAnonymousExecutable(CtAnonymousExecutable impl) {
596 		writeAnnotations(impl);
597 		writeModifiers(impl);
598 		impl.getBody().accept(this);
599 	}
600 
601 	public <T, E extends CtExpression<?>> void visitCtArrayAccess(
602 			CtArrayAccess<T, E> arrayAccess) {
603 		enterCtExpression(arrayAccess);
604 		scan(arrayAccess.getTarget());
605 		write("[").scan(arrayAccess.getIndexExpression()).write("]");
606 		exitCtExpression(arrayAccess);
607 	}
608 
609 	public <T> void visitCtArrayTypeReference(CtArrayTypeReference<T> reference) {
610 		scan(reference.getComponentType());
611 		if (!context.skipArray) {
612 			write("[]");
613 		}
614 	}
615 
616 	public <T> void visitCtAssert(CtAssert<T> asserted) {
617 		enterCtStatement(asserted);
618 		write("assert ");
619 		scan(asserted.getAssertExpression());
620 		if (asserted.getExpression() != null) {
621 			write(" : ");
622 			scan(asserted.getExpression());
623 		}
624 
625 	}
626 
627 	public <T, A extends T> void visitCtAssignment(
628 			CtAssignment<T, A> assignement) {
629 		enterCtStatement(assignement);
630 		enterCtExpression(assignement);
631 		scan(assignement.getAssigned());
632 		write(" = ");
633 		scan(assignement.getAssignment());
634 		exitCtExpression(assignement);
635 	}
636 
637 	public <T> void visitCtBinaryOperator(CtBinaryOperator<T> operator) {
638 		enterCtExpression(operator);
639 		boolean paren = (operator.getParent() instanceof CtBinaryOperator)
640 				|| (operator.getParent() instanceof CtUnaryOperator);
641 		if (paren) {
642 			write("(");
643 		}
644 		scan(operator.getLeftHandOperand());
645 		write(" ").writeOperator(operator.getKind()).write(" ");
646 		scan(operator.getRightHandOperand());
647 		if (paren) {
648 			write(")");
649 		}
650 		exitCtExpression(operator);
651 	}
652 
653 	public <R> void visitCtBlock(CtBlock<R> block) {
654 		enterCtStatement(block);
655 		write("{").incTab();
656 		for (CtStatement e : block.getStatements()) {
657 			if (!e.isImplicit()) {
658 				writeln();
659 				writeStatement(e);
660 			}
661 		}
662 		decTab().writeln().write("}");
663 	}
664 
665 	public void visitCtBreak(CtBreak breakStatement) {
666 		enterCtStatement(breakStatement);
667 		write("break");
668 		if (breakStatement.getTargetLabel() != null) {
669 			write(" " + breakStatement.getTargetLabel());
670 		}
671 	}
672 
673 	@SuppressWarnings("unchecked")
674 	public <E> void visitCtCase(CtCase<E> caseStatement) {
675 		enterCtStatement(caseStatement);
676 		if (caseStatement.getCaseExpression() != null) {
677 			write("case ");
678 			// writing enum case expression
679 			if ((caseStatement.getCaseExpression() instanceof CtFieldAccess)
680 					&& ((CtFieldAccess) caseStatement.getCaseExpression())
681 							.getVariable().getType().getQualifiedName().equals(
682 									((CtFieldAccess) caseStatement
683 											.getCaseExpression()).getVariable()
684 											.getDeclaringType()
685 											.getQualifiedName())) {
686 				write(((CtFieldAccess) caseStatement.getCaseExpression())
687 						.getVariable().getSimpleName());
688 			} else {
689 				scan(caseStatement.getCaseExpression());
690 			}
691 		} else {
692 			write("default");
693 		}
694 		write(" :").incTab();
695 
696 		for (CtStatement s : caseStatement.getStatements()) {
697 			writeln().writeStatement(s);
698 		}
699 		decTab();
700 	}
701 
702 	public void visitCtCatch(CtCatch catchBlock) {
703 		write(" catch (");
704 		scan(catchBlock.getParameter());
705 		write(") ");
706 		scan(catchBlock.getBody());
707 	}
708 
709 	public DefaultJavaPrettyPrinter writeExtendsClause(CtClass<?> c) {
710 		if (c.getSuperclass() != null) {
711 			write(" extends ");
712 			scan(c.getSuperclass());
713 		}
714 		return this;
715 	}
716 
717 	public DefaultJavaPrettyPrinter writeImplementsClause(CtType<?> t) {
718 		if (t.getSuperInterfaces().size() > 0) {
719 			write(" implements ");
720 			for (CtTypeReference<?> ref : t.getSuperInterfaces()) {
721 				scan(ref);
722 				write(" , ");
723 			}
724 			removeLastChar();
725 		}
726 		return this;
727 	}
728 
729 	public <T> void visitCtClass(CtClass<T> ctClass) {
730 		SortedList<CtElement> lst = new SortedList<CtElement>(
731 				new CtLineElementComparator());
732 		if ((ctClass.getSimpleName() != null)
733 				&& (ctClass.getSimpleName().length() > 0)) {
734 			visitCtType(ctClass);
735 			write("class " + ctClass.getSimpleName());
736 
737 			writeGenericsParameter(ctClass.getFormalTypeParameters());
738 
739 			writeExtendsClause(ctClass);
740 			writeImplementsClause(ctClass);
741 			for (CtConstructor<T> c : ctClass.getConstructors()) {
742 				if (!c.isImplicit()) {
743 					lst.add(c);
744 				}
745 			}
746 		}
747 		lst.addAll(ctClass.getAnonymousExecutables());
748 		lst.addAll(ctClass.getNestedTypes());
749 		lst.addAll(ctClass.getFields());
750 		lst.addAll(ctClass.getMethods());
751 
752 		context.currentThis.push(ctClass.getReference());
753 		write(" {").incTab();
754 		for (CtElement el : lst) {
755 			writeln().scan(el).writeln();
756 		}
757 		decTab().writeln().write("}");
758 		context.currentThis.pop();
759 	}
760 
761 	public <T> void visitCtConditional(CtConditional<T> conditional) {
762 		enterCtExpression(conditional);
763 		scan(conditional.getCondition());
764 		write(" ? ");
765 		scan(conditional.getThenExpression());
766 		write(" : ");
767 		scan(conditional.getElseExpression());
768 		exitCtExpression(conditional);
769 	}
770 
771 	public <T> void visitCtConstructor(CtConstructor<T> c) {
772 		visitCtNamedElement(c);
773 		writeGenericsParameter(c.getFormalTypeParameters());
774 		write(c.getDeclaringType().getSimpleName());
775 		write("(");
776 		if (c.getParameters().size() > 0) {
777 			for (CtParameter<?> p : c.getParameters()) {
778 				visitCtParameter(p);
779 				write(" ,");
780 			}
781 			removeLastChar();
782 		}
783 		write(") ");
784 		if ((c.getThrownTypes() != null) && (c.getThrownTypes().size() > 0)) {
785 			write("throws ");
786 			for (CtTypeReference<?> ref : c.getThrownTypes()) {
787 				scan(ref);
788 				write(" , ");
789 			}
790 			removeLastChar();
791 			write(" ");
792 		}
793 		scan(c.getBody());
794 	}
795 
796 	public void visitCtContinue(CtContinue continueStatement) {
797 		enterCtStatement(continueStatement);
798 		write("continue");
799 	}
800 
801 	public void visitCtDo(CtDo doLoop) {
802 		enterCtStatement(doLoop);
803 		write("do ");
804 		writeStatement(doLoop.getBody());
805 		write(" while (");
806 		scan(doLoop.getLoopingExpression());
807 		write(" )");
808 		// write(";");
809 	}
810 
811 	private void writeEnumField(CtField<?> f) {
812 		write(f.getSimpleName());
813 		if (f.getDefaultExpression() != null) {
814 			CtNewClass<?> nc = (CtNewClass<?>) f.getDefaultExpression();
815 			if (nc.getArguments().size() > 0) {
816 				write("(" + nc.getArguments().get(0) + ")");
817 			}
818 			scan(nc.getAnonymousClass());
819 		}
820 	}
821 
822 	public <T extends Enum<?>> void visitCtEnum(CtEnum<T> ctEnum) {
823 		visitCtSimpleType(ctEnum);
824 		write("enum " + ctEnum.getSimpleName());
825 		if (ctEnum.getSuperInterfaces().size() > 0) {
826 			write(" implements ");
827 			for (CtTypeReference<?> ref : ctEnum.getSuperInterfaces()) {
828 				scan(ref);
829 				write(" , ");
830 			}
831 			removeLastChar();
832 		}
833 		write(" {").incTab().writeln();
834 		List<CtField<?>> l1 = new ArrayList<CtField<?>>();
835 		List<CtField<?>> l2 = new ArrayList<CtField<?>>();
836 		for (CtField<?> ec : ctEnum.getFields()) {
837 			if (ec.getType() == null) {
838 				l1.add(ec);
839 			} else {
840 				l2.add(ec);
841 			}
842 		}
843 		if (l1.size() > 0) {
844 			for (CtField<?> ec : l1) {
845 				writeEnumField(ec);
846 				write(", ");
847 			}
848 			removeLastChar();
849 			write(";");
850 		}
851 		for (CtField<?> ec : l2) {
852 			writeln().scan(ec);
853 		}
854 		for (CtConstructor<?> c : ctEnum.getConstructors()) {
855 			if (!c.isImplicit()) {
856 				writeln().scan(c);
857 			}
858 		}
859 		
860 		SortedList<CtElement> lst = new SortedList<CtElement>(
861 				new CtLineElementComparator());
862 		
863 		lst.addAll(ctEnum.getAnonymousExecutables());
864 		lst.addAll(ctEnum.getNestedTypes());
865 		lst.addAll(ctEnum.getMethods());
866 
867 		context.currentThis.push(ctEnum.getReference());
868 		for (CtElement el : lst) {
869 			writeln().scan(el).writeln();
870 		}
871 		decTab().writeln().write("}");
872 		context.currentThis.pop();
873 	}
874 
875 	public <T> void visitCtExecutableReference(
876 			CtExecutableReference<T> reference) {
877 		scan(reference.getDeclaringType());
878 		write(".");
879 		if (reference.getSimpleName().equals("<init>")) {
880 			write(reference.getDeclaringType().getSimpleName());
881 		} else {
882 			write(reference.getSimpleName());
883 		}
884 		writeGenericsParameter(reference.getActualTypeArguments());
885 		writeParameters(reference.getParameterTypes());
886 	}
887 
888 	public <T> void visitCtField(CtField<T> f) {
889 		visitCtNamedElement(f);
890 		scan(f.getType());
891 		write(" ");
892 		write(f.getSimpleName());
893 
894 		if ((f.getParent() == null)
895 				|| !CtAnnotationType.class.isAssignableFrom(f.getParent()
896 						.getClass())) {
897 			if (f.getDefaultExpression() != null) {
898 				write(" = ");
899 				scan(f.getDefaultExpression());
900 			}
901 		} else {
902 			write("()");
903 			if (f.getDefaultExpression() != null) {
904 				write(" default ");
905 				scan(f.getDefaultExpression());
906 			}
907 		}
908 		write(";");
909 	}
910 
911 	public <T> void visitCtFieldAccess(CtFieldAccess<T> fieldAccess) {
912 		enterCtExpression(fieldAccess);
913 		if (fieldAccess.getTarget() != null) {
914 			scan(fieldAccess.getTarget());
915 			write(".");
916 		}
917 		context.ignoreGenerics = true;
918 		scan(fieldAccess.getVariable());
919 		context.ignoreGenerics = false;
920 		exitCtExpression(fieldAccess);
921 	}
922 
923 	public <T> void visitCtFieldReference(CtFieldReference<T> reference) {
924 		if (reference.getSimpleName().equals("this")) {
925 			if (context.currentThis.isEmpty()
926 					|| !reference.getType().equals(context.currentThis.peek())) {
927 				context.ignoreGenerics = true;
928 				scan(reference.getDeclaringType());
929 				write(".");
930 				context.ignoreGenerics = false;
931 			}
932 		} else {
933 			boolean isStatic = false;
934 			if (reference.getSimpleName().equals("class")) {
935 				isStatic = true;
936 			} else if (reference.getSimpleName().equals("super")) {
937 				isStatic = false;
938 			} else {
939 				isStatic = reference.isStatic();
940 			}
941 
942 			boolean printType = true;
943 			if (reference.isFinal() && reference.isStatic()) {
944 				if (context.currentTopLevel != null) {
945 					CtTypeReference<?> ref = reference.getDeclaringType();
946 					CtTypeReference<?> ref2 = context.currentTopLevel
947 							.getReference();
948 					// print type if not annonymous class ref and not within the
949 					// current scope
950 					printType = !ref.getSimpleName().equals("")
951 							&& !(ref.equals(ref2));
952 				} else {
953 					printType = true;
954 				}
955 			}
956 
957 			if (isStatic && printType) {
958 				context.ignoreGenerics = true;
959 				scan(reference.getDeclaringType());
960 				context.ignoreGenerics = false;
961 				write(".");
962 			}
963 		}
964 		write(reference.getSimpleName());
965 	}
966 
967 	public void visitCtFor(CtFor forLoop) {
968 		enterCtStatement(forLoop);
969 		write("for (");
970 		List<CtStatement> st = forLoop.getForInit();
971 		if (st.size() > 0) {
972 			scan(st.get(0));
973 		}
974 		if (st.size() > 1) {
975 			context.noTypeDecl = true;
976 			for (int i = 1; i < st.size(); i++) {
977 				write(", ");
978 				scan(st.get(i));
979 			}
980 			context.noTypeDecl = false;
981 		}
982 		write(" ; ");
983 		scan(forLoop.getExpression());
984 		write(" ; ");
985 		for (CtStatement s : forLoop.getForUpdate()) {
986 			scan(s);
987 			write(" , ");
988 		}
989 		if (forLoop.getForUpdate().size() > 0) {
990 			removeLastChar();
991 		}
992 		write(")");
993 		if (forLoop.getBody() instanceof CtBlock) {
994 			write(" ");
995 			scan(forLoop.getBody());
996 		} else {
997 			incTab().writeln();
998 			writeStatement(forLoop.getBody());
999 			decTab();
1000 		}
1001 	}
1002 
1003 	public void visitCtForEach(CtForEach foreach) {
1004 		enterCtStatement(foreach);
1005 		write("for (");
1006 		scan(foreach.getVariable());
1007 		write(" : ");
1008 		scan(foreach.getExpression());
1009 		write(")");
1010 
1011 		if (foreach.getBody() instanceof CtBlock) {
1012 			write(" ");
1013 			scan(foreach.getBody());
1014 		} else {
1015 			incTab().writeln();
1016 			writeStatement(foreach.getBody());
1017 			decTab();
1018 		}
1019 	}
1020 
1021 	public void visitCtIf(CtIf ifElement) {
1022 		enterCtStatement(ifElement);
1023 		write("if (");
1024 		scan(ifElement.getCondition());
1025 		write(")");
1026 		if (ifElement.getThenStatement() instanceof CtBlock) {
1027 			write(" ");
1028 			scan(ifElement.getThenStatement());
1029 			write(" ");
1030 		} else {
1031 			incTab().writeln();
1032 			writeStatement(ifElement.getThenStatement());
1033 			decTab().writeln();
1034 		}
1035 		if (ifElement.getElseStatement() != null) {
1036 			write("else");
1037 			if (ifElement.getElseStatement() instanceof CtIf) {
1038 				write(" ");
1039 				scan(ifElement.getElseStatement());
1040 			} else if (ifElement.getElseStatement() instanceof CtBlock) {
1041 				write(" ");
1042 				scan(ifElement.getElseStatement());
1043 			} else {
1044 				incTab().writeln();
1045 				writeStatement(ifElement.getElseStatement());
1046 				decTab().writeln();
1047 			}
1048 		}
1049 	}
1050 
1051 	public <T> void visitCtInterface(CtInterface<T> intrface) {
1052 		visitCtType(intrface);
1053 		write("interface " + intrface.getSimpleName());
1054 		if (intrface.getFormalTypeParameters() != null) {
1055 			writeGenericsParameter(intrface.getFormalTypeParameters());
1056 		}
1057 
1058 		if (intrface.getSuperInterfaces().size() > 0) {
1059 			write(" extends ");
1060 			for (CtTypeReference<?> ref : intrface.getSuperInterfaces()) {
1061 				scan(ref);
1062 				write(" , ");
1063 			}
1064 			removeLastChar();
1065 		}
1066 		write(" {").incTab();
1067 		SortedList<CtElement> lst = new SortedList<CtElement>(
1068 				new CtLineElementComparator());
1069 		lst.addAll(intrface.getNestedTypes());
1070 		lst.addAll(intrface.getFields());
1071 		lst.addAll(intrface.getMethods());
1072 		// Content
1073 		for (CtElement e : lst) {
1074 			writeln().scan(e);
1075 		}
1076 		decTab().writeln().write("}");
1077 	}
1078 
1079 	public <T> void visitCtInvocation(CtInvocation<T> invocation) {
1080 		enterCtStatement(invocation);
1081 		enterCtExpression(invocation);
1082 		if (invocation.getExecutable().getSimpleName().equals("<init>")) {
1083 			// It's a constructor (super or this)
1084 			CtType<?> parentType = invocation.getParent(CtType.class);
1085 			if ((parentType != null)
1086 					&& (parentType.getQualifiedName() != null)
1087 					&& parentType.getQualifiedName().equals(
1088 							invocation.getExecutable().getDeclaringType()
1089 									.getQualifiedName())) {
1090 				write("this");
1091 			} else {
1092 				write("super");
1093 			}
1094 		} else {
1095 			// It's a method invocation
1096 			if (invocation.getExecutable().isStatic()) {
1097 				CtTypeReference<?> type = invocation.getExecutable()
1098 						.getDeclaringType();
1099 				if (isHiddenByField(invocation.getParent(CtType.class), type)) {
1100 					importsContext.imports.remove(type.getSimpleName());
1101 				}
1102 				context.ignoreGenerics = true;
1103 				scan(type);
1104 				context.ignoreGenerics = false;
1105 				write(".");
1106 			} else if (invocation.getTarget() != null) {
1107 				context.enterTarget();
1108 				scan(invocation.getTarget());
1109 				context.exitTarget();
1110 				write(".");
1111 			}
1112 			write(invocation.getExecutable().getSimpleName());
1113 		}
1114 		write("(");
1115 		boolean remove = false;
1116 		for (CtExpression<?> e : invocation.getArguments()) {
1117 			scan(e);
1118 			write(" ,");
1119 			remove = true;
1120 		}
1121 		if (remove) {
1122 			removeLastChar();
1123 		}
1124 		write(")");
1125 		exitCtExpression(invocation);
1126 	}
1127 
1128 	/**
1129 	 * Quotes a string.
1130 	 */
1131 	public static String quote(String s) {
1132 		StringBuffer buf = new StringBuffer();
1133 		for (int i = 0; i < s.length(); i++) {
1134 			char ch = s.charAt(i);
1135 			switch (ch) {
1136 			case '\n':
1137 				buf.append("\\n");
1138 				break;
1139 			case '\t':
1140 				buf.append("\\t");
1141 				break;
1142 			case '\b':
1143 				buf.append("\\b");
1144 				break;
1145 			case '\f':
1146 				buf.append("\\f");
1147 				break;
1148 			case '\r':
1149 				buf.append("\\r");
1150 				break;
1151 			case '\"':
1152 				buf.append("\\\"");
1153 				break;
1154 			case '\'':
1155 				buf.append("\\\'");
1156 				break;
1157 			case '\\':
1158 				buf.append("\\\\");
1159 				break;
1160 			default:
1161 				// if (ch < 32 || 128 <= ch && ch < 255) {
1162 				// buf.append("\\");
1163 				// buf.append((char) ('0' + (ch >> 6) % 8));
1164 				// buf.append((char) ('0' + (ch >> 3) % 8));
1165 				// buf.append((char) ('0' + (ch) % 8));
1166 				// } else {
1167 				buf.append(ch);
1168 				// }
1169 			}
1170 		}
1171 		return buf.toString();
1172 	}
1173 
1174 	public <T> void visitCtLiteral(CtLiteral<T> literal) {
1175 		enterCtExpression(literal);
1176 		if (literal.getValue() == null) {
1177 			write("null");
1178 		} else if (literal.getValue() instanceof Long) {
1179 			write(literal.getValue() + "L");
1180 		} else if (literal.getValue() instanceof Float) {
1181 			write(literal.getValue() + "F");
1182 		} else if (literal.getValue() instanceof Character) {
1183 			write("'");
1184 			write(quote(String.valueOf(literal.getValue())));
1185 			write("'");
1186 		} else if (literal.getValue() instanceof String) {
1187 			write("\"" + quote((String) literal.getValue()) + "\"");
1188 		} else if (literal.getValue() instanceof Class) {
1189 			write(((Class<?>) literal.getValue()).getName());
1190 		} else if (literal.getValue() instanceof CtReference) {
1191 			scan((CtReference) literal.getValue());
1192 		} else {
1193 			write(literal.getValue().toString());
1194 		}
1195 		exitCtExpression(literal);
1196 	}
1197 
1198 	public <T> DefaultJavaPrettyPrinter writeLocalVariable(
1199 			CtLocalVariable<T> localVariable) {
1200 		if (!context.noTypeDecl) {
1201 			writeModifiers(localVariable);
1202 			scan(localVariable.getType());
1203 			write(" ");
1204 		}
1205 		write(localVariable.getSimpleName());
1206 		if (localVariable.getDefaultExpression() != null) {
1207 			write(" = ");
1208 			scan(localVariable.getDefaultExpression());
1209 		}
1210 		return this;
1211 	}
1212 
1213 	public <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
1214 		enterCtStatement(localVariable);
1215 		writeLocalVariable(localVariable);
1216 	}
1217 
1218 	public <T> void visitCtLocalVariableReference(
1219 			CtLocalVariableReference<T> reference) {
1220 		write(reference.getSimpleName());
1221 	}
1222 
1223 	public DefaultJavaPrettyPrinter writeTypeReference(CtTypeReference<?> t) {
1224 		scan(t);
1225 		return this;
1226 	}
1227 
1228 	public DefaultJavaPrettyPrinter writeExecutableParameters(CtExecutable<?> e) {
1229 		if (e.getParameters().size() > 0) {
1230 			for (CtParameter<?> p : e.getParameters()) {
1231 				visitCtParameter(p);
1232 				write(", ");
1233 			}
1234 			removeLastChar();
1235 		}
1236 		return this;
1237 	}
1238 
1239 	public DefaultJavaPrettyPrinter writeThrowsClause(CtExecutable<?> e) {
1240 		if (e.getThrownTypes().size() > 0) {
1241 			write(" throws ");
1242 			for (CtTypeReference<?> ref : e.getThrownTypes()) {
1243 				scan(ref);
1244 				write(", ");
1245 			}
1246 			removeLastChar();
1247 		}
1248 		return this;
1249 	}
1250 
1251 	public <T> void visitCtMethod(CtMethod<T> m) {
1252 		visitCtNamedElement(m);
1253 		writeGenericsParameter(m.getFormalTypeParameters());
1254 		scan(m.getType());
1255 		write(" ");
1256 		write(m.getSimpleName());
1257 		write("(");
1258 		writeExecutableParameters(m);
1259 		write(")");
1260 		writeThrowsClause(m);
1261 		if (m.getBody() != null) {
1262 			write(" ");
1263 			visitCtBlock(m.getBody());
1264 			if (m.getBody().getPosition() != null) {
1265 				if (m.getBody().getPosition().getCompilationUnit() == sourceCompilationUnit) {
1266 					if (m.getBody().getStatements().isEmpty()
1267 							|| !(m.getBody().getStatements().get(
1268 									m.getBody().getStatements().size() - 1) instanceof CtReturn)) {
1269 						lineNumberMapping.put(line, m.getBody().getPosition()
1270 								.getEndLine());
1271 					}
1272 				} else {
1273 					undefLine(line);
1274 				}
1275 			} else {
1276 				undefLine(line);
1277 			}
1278 		} else {
1279 			write(";");
1280 		}
1281 	}
1282 
1283 	public void reset() {
1284 		importsContext = new ImportScanner();
1285 		sbf = new StringBuffer();
1286 	}
1287 
1288 	public DefaultJavaPrettyPrinter writeModifiers(CtModifiable m) {
1289 		for (ModifierKind mod : m.getModifiers()) {
1290 			write(mod.toString().toLowerCase() + " ");
1291 		}
1292 		return this;
1293 	}
1294 
1295 	public void visitCtNamedElement(CtNamedElement e) {
1296 		// Write comments
1297 		if (context.printDocs && (e.getDocComment() != null)) {
1298 			write("/** ").writeln();
1299 			for (String com : e.getDocComment().split("\n")) {
1300 				write(" *" + com).writeln();
1301 			}
1302 			write(" */").writeln();
1303 		}
1304 		// Write element parameters (Annotations)
1305 		writeAnnotations(e);
1306 		writeModifiers(e);
1307 	}
1308 
1309 	@SuppressWarnings("unchecked")
1310 	public <T> void visitCtNewArray(CtNewArray<T> newArray) {
1311 		enterCtExpression(newArray);
1312 
1313 		if (!(context.currentTopLevel instanceof CtAnnotationType)) {
1314 			CtTypeReference<?> ref = newArray.getType();
1315 
1316 			if (ref != null) {
1317 				write("new ");
1318 			}
1319 
1320 			context.skipArray = true;
1321 			scan(ref);
1322 			context.skipArray = false;
1323 			for (int i = 0; ref instanceof CtArrayTypeReference; i++) {
1324 				write("[");
1325 				if (newArray.getDimensionExpressions().size() > i) {
1326 					scan(newArray.getDimensionExpressions().get(i));
1327 				}
1328 				write("]");
1329 				ref = ((CtArrayTypeReference) ref).getComponentType();
1330 			}
1331 		}
1332 		if (newArray.getDimensionExpressions().size() == 0) {
1333 			write("{ ");
1334 			for (CtExpression e : newArray.getElements()) {
1335 				scan(e);
1336 				write(" , ");
1337 			}
1338 			if (newArray.getElements().size() > 0) {
1339 				removeLastChar();
1340 			}
1341 			write(" }");
1342 		}
1343 		exitCtExpression(newArray);
1344 	}
1345 
1346 	public <T> void visitCtNewClass(CtNewClass<T> newClass) {
1347 		enterCtStatement(newClass);
1348 		enterCtExpression(newClass);
1349 
1350 		if (newClass.getTarget() != null) {
1351 			scan(newClass.getTarget()).write(".");
1352 		}
1353 
1354 		if (newClass.getAnonymousClass() != null) {
1355 			write("new ");
1356 			if (newClass.getAnonymousClass().getSuperclass() != null) {
1357 				scan(newClass.getAnonymousClass().getSuperclass());
1358 			} else if (newClass.getAnonymousClass().getSuperInterfaces().size() > 0) {
1359 				for (CtTypeReference<?> ref : newClass.getAnonymousClass()
1360 						.getSuperInterfaces()) {
1361 					scan(ref);
1362 				}
1363 			}
1364 			write("(");
1365 			for (CtExpression<?> exp : newClass.getArguments()) {
1366 				scan(exp);
1367 				write(", ");
1368 			}
1369 			if (newClass.getArguments().size() > 0) {
1370 				removeLastChar();
1371 			}
1372 			write(")");
1373 			scan(newClass.getAnonymousClass());
1374 		} else {
1375 			write("new ").scan(newClass.getType());
1376 
1377 			if ((newClass.getExecutable() != null)
1378 					&& (newClass.getExecutable().getActualTypeArguments() != null)) {
1379 				writeGenericsParameter(newClass.getExecutable()
1380 						.getActualTypeArguments());
1381 			}
1382 			write("(");
1383 			boolean remove = false;
1384 			for (CtCodeElement e : newClass.getArguments()) {
1385 				scan(e);
1386 				write(" , ");
1387 				remove = true;
1388 			}
1389 			if (remove) {
1390 				removeLastChar();
1391 			}
1392 
1393 			write(")");
1394 		}
1395 		exitCtExpression(newClass);
1396 	}
1397 
1398 	public <T, A extends T> void visitCtOperatorAssignement(
1399 			CtOperatorAssignment<T, A> assignment) {
1400 		enterCtStatement(assignment);
1401 		enterCtExpression(assignment);
1402 		scan(assignment.getAssigned());
1403 		write(" ");
1404 		writeOperator(assignment.getKind());
1405 		write("= ");
1406 		scan(assignment.getAssignment());
1407 		exitCtExpression(assignment);
1408 	}
1409 
1410 	public void visitCtPackage(CtPackage ctPackage) {
1411 		if (!ctPackage.getQualifiedName().equals(
1412 				CtPackage.TOP_LEVEL_PACKAGE_NAME)) {
1413 			if (context.currentTopLevel == null) {
1414 				for (CtAnnotation<?> a : ctPackage.getAnnotations()) {
1415 					scan(a);
1416 				}
1417 			}
1418 			write("package " + ctPackage.getQualifiedName() + ";");
1419 		}
1420 	}
1421 
1422 	public void visitCtPackageReference(CtPackageReference reference) {
1423 		write(reference.getSimpleName());
1424 	}
1425 
1426 	public <T> void visitCtParameter(CtParameter<T> parameter) {
1427 		writeAnnotations(parameter);
1428 		writeModifiers(parameter);
1429 		if (parameter.isVarArgs()) {
1430 			scan(((CtArrayTypeReference<T>) parameter.getType())
1431 					.getComponentType());
1432 			write("...");
1433 		} else {
1434 			scan(parameter.getType());
1435 		}
1436 		write(" ");
1437 		write(parameter.getSimpleName());
1438 	}
1439 
1440 	public <T> void visitCtParameterReference(CtParameterReference<T> reference) {
1441 		write(reference.getSimpleName());
1442 	}
1443 
1444 	public <R> void visitCtReturn(CtReturn<R> returnStatement) {
1445 		enterCtStatement(returnStatement);
1446 		write("return ");
1447 		scan(returnStatement.getReturnedExpression());
1448 	}
1449 
1450 	<T> void visitCtSimpleType(CtSimpleType<T> type) {
1451 		mapLine(line, type);
1452 		if (type.isTopLevel()) {
1453 			context.currentTopLevel = type;
1454 		}
1455 		visitCtNamedElement(type);
1456 	}
1457 
1458 	public <R> void visitCtStatementList(CtStatementList<R> statements) {
1459 		for (CtStatement s : statements.getStatements()) {
1460 			scan(s);
1461 		}
1462 	}
1463 
1464 	public <E> void visitCtSwitch(CtSwitch<E> switchStatement) {
1465 		enterCtStatement(switchStatement);
1466 		write("switch (");
1467 		scan(switchStatement.getSelector());
1468 		write(") {").incTab();
1469 		for (CtCase<?> c : switchStatement.getCases()) {
1470 			writeln().scan(c);
1471 		}
1472 		decTab().writeln().write("}");
1473 	}
1474 
1475 	public void visitCtSynchronized(CtSynchronized synchro) {
1476 		enterCtStatement(synchro);
1477 		write("synchronized");
1478 		if (synchro.getExpression() != null) {
1479 			write("(");
1480 			scan(synchro.getExpression());
1481 			write(") ");
1482 		}
1483 		scan(synchro.getBlock());
1484 	}
1485 
1486 	public void visitCtThrow(CtThrow throwStatement) {
1487 		enterCtStatement(throwStatement);
1488 		write("throw ");
1489 		scan(throwStatement.getThrownExpression());
1490 	}
1491 
1492 	public void visitCtTry(CtTry tryBlock) {
1493 		enterCtStatement(tryBlock);
1494 		write("try ");
1495 		scan(tryBlock.getBody());
1496 		for (CtCatch c : tryBlock.getCatchers()) {
1497 			scan(c);
1498 		}
1499 
1500 		if (tryBlock.getFinalizer() != null) {
1501 			write(" finally ");
1502 			scan(tryBlock.getFinalizer());
1503 		}
1504 	}
1505 
1506 	<T> void visitCtType(CtType<T> type) {
1507 		visitCtSimpleType(type);
1508 	}
1509 
1510 	public void visitCtTypeParameter(CtTypeParameter typeParameter) {
1511 		write(typeParameter.getName());
1512 		if (!typeParameter.getBounds().isEmpty()) {
1513 			write(" extends ");
1514 			for (CtTypeReference<?> ref : typeParameter.getBounds()) {
1515 				scan(ref);
1516 				write(" & ");
1517 			}
1518 			removeLastChar();
1519 		}
1520 	}
1521 
1522 	public void visitCtTypeParameterReference(CtTypeParameterReference ref) {
1523 		// write(ref.getSimpleName());
1524 
1525 		if (importsContext.isImported(ref) || context.printShortName) {
1526 			write(ref.getSimpleName());
1527 		} else {
1528 			write(ref.getQualifiedName());
1529 		}
1530 		if (!context.ignoreGenerics) {
1531 			writeGenericsParameter(ref.getActualTypeArguments());
1532 		}
1533 		if (!ref.getBounds().isEmpty()
1534 				&& !((ref.getBounds().size() == 1) && ref.getBounds().get(0)
1535 						.getQualifiedName().equals("java.lang.Object"))) {
1536 			if (ref.isUpper()) {
1537 				write(" extends ");
1538 			} else {
1539 				write(" super ");
1540 			}
1541 			for (CtTypeReference<?> b : ref.getBounds()) {
1542 				scan(b);
1543 				write(" & ");
1544 			}
1545 			removeLastChar();
1546 		}
1547 	}
1548 
1549 	public <T> void visitCtTypeReference(CtTypeReference<T> ref) {
1550 		if (ref.isPrimitive()) {
1551 			write(ref.getSimpleName());
1552 			return;
1553 		}
1554 		if ((importsContext.isImported(ref) && !context.ignoreImport)
1555 				|| context.printShortName) {
1556 			write(ref.getSimpleName());
1557 		} else {
1558 			if (ref.getDeclaringType() != null) {
1559 				if (context.currentTopLevel != null) {
1560 					boolean ign = context.ignoreGenerics;
1561 					context.ignoreGenerics = true;
1562 					scan(ref.getDeclaringType());
1563 					write(".");
1564 					context.ignoreGenerics = ign;
1565 				}
1566 				write(ref.getSimpleName());
1567 			} else {
1568 				write(ref.getQualifiedName());
1569 			}
1570 		}
1571 		if (!context.ignoreGenerics) {
1572 			writeGenericsParameter(ref.getActualTypeArguments());
1573 		}
1574 	}
1575 
1576 	public <T> void visitCtUnaryOperator(CtUnaryOperator<T> operator) {
1577 		enterCtStatement(operator);
1578 		enterCtExpression(operator);
1579 		preWriteUnaryOperator(operator.getKind());
1580 		context.enterTarget();
1581 		scan(operator.getOperand());
1582 		context.exitTarget();
1583 		postWriteUnaryOperator(operator.getKind());
1584 		exitCtExpression(operator);
1585 	}
1586 
1587 	public <T> void visitCtVariableAccess(CtVariableAccess<T> variableAccess) {
1588 		enterCtExpression(variableAccess);
1589 		write(variableAccess.getVariable().getSimpleName());
1590 		exitCtExpression(variableAccess);
1591 	}
1592 
1593 	public void visitCtWhile(CtWhile whileLoop) {
1594 		enterCtStatement(whileLoop);
1595 		write("while (");
1596 		scan(whileLoop.getLoopingExpression());
1597 		write(")");
1598 
1599 		if (whileLoop.getBody() instanceof CtBlock) {
1600 			write(" ");
1601 			scan(whileLoop.getBody());
1602 		} else {
1603 			incTab().writeln();
1604 			writeStatement(whileLoop.getBody());
1605 			decTab();
1606 		}
1607 	}
1608 
1609 	/**
1610 	 * Generates a string.
1611 	 */
1612 	public DefaultJavaPrettyPrinter write(String s) {
1613 		if (s != null) {
1614 			sbf.append(s);
1615 		}
1616 		return this;
1617 	}
1618 
1619 	/**
1620 	 * Writes the annotations for the given element.
1621 	 */
1622 	public DefaultJavaPrettyPrinter writeAnnotations(CtElement e) {
1623 		for (CtAnnotation<?> a : e.getAnnotations()) {
1624 			a.accept(this);
1625 		}
1626 		return this;
1627 	}
1628 
1629 	/**
1630 	 * Writes an annotation element.
1631 	 */
1632 	public DefaultJavaPrettyPrinter writeAnnotationElement(Object value) {
1633 		if (value instanceof CtTypeReference) {
1634 			context.ignoreGenerics = true;
1635 			scan((CtTypeReference<?>) value).write(".class");
1636 			context.ignoreGenerics = false;
1637 		} else if (value instanceof CtFieldReference) {
1638 			scan(((CtFieldReference<?>) value).getDeclaringType());
1639 			write("." + ((CtFieldReference<?>) value).getSimpleName());
1640 		} else if (value instanceof CtReference) {
1641 			scan((CtReference) value);
1642 		} else if (value instanceof CtElement) {
1643 			scan((CtElement) value);
1644 		} else if (value instanceof String) {
1645 			write("\"" + value.toString() + "\"");
1646 		} else if (value instanceof Collection) {
1647 			write("{");
1648 			if (!((Collection<?>) value).isEmpty()) {
1649 				for (Object obj : (Collection<?>) value) {
1650 					writeAnnotationElement(obj);
1651 					write(" ,");
1652 				}
1653 				removeLastChar();
1654 			}
1655 			write("}");
1656 		} else {
1657 			write(value.toString());
1658 		}
1659 		return this;
1660 	}
1661 
1662 	/**
1663 	 * Writes a generics parameter.
1664 	 */
1665 	public DefaultJavaPrettyPrinter writeGenericsParameter(
1666 			Collection<CtTypeReference<?>> params) {
1667 		if (params == null) {
1668 			return this;
1669 		}
1670 		if (params.size() > 0) {
1671 			write("<");
1672 			context.ignoreImport = true;
1673 			for (CtTypeReference<?> param : params) {
1674 				scan(param);
1675 				write(", ");
1676 			}
1677 			context.ignoreImport = false;
1678 			removeLastChar();
1679 			write("> ");
1680 		}
1681 		return this;
1682 	}
1683 
1684 	/**
1685 	 * Write the compilation unit header.
1686 	 */
1687 	public DefaultJavaPrettyPrinter writeHeader(List<CtSimpleType<?>> types) {
1688 		if (!types.isEmpty()) {
1689 			CtPackage pack = types.get(0).getPackage();
1690 			scan(pack).writeln().writeln();
1691 			if ((sourceCompilationUnit != null)
1692 					&& !sourceCompilationUnit.isAutoImport()) {
1693 				for (Import i : sourceCompilationUnit.getManualImports()) {
1694 					write(i + ";").writeln();
1695 				}
1696 			} else {
1697 				for (CtTypeReference<?> ref : importsContext.imports.values()) {
1698 					// ignore non-top-level type
1699 					if (ref.getPackage() != null) {
1700 						// ignore java.lang package
1701 						if (!ref.getPackage().getSimpleName().equals(
1702 								"java.lang")) {
1703 							// ignore type in same package
1704 							if (!ref.getPackage().getSimpleName().equals(
1705 									pack.getQualifiedName())) {
1706 								write("import " + ref.getQualifiedName() + ";")
1707 										.writeln();
1708 							}
1709 						}
1710 					}
1711 				}
1712 			}
1713 			writeln();
1714 		}
1715 		return this;
1716 	}
1717 
1718 	int line = 1;
1719 
1720 	/**
1721 	 * Generates a new line starting with the current number of tabs.
1722 	 */
1723 	public DefaultJavaPrettyPrinter writeln() {
1724 		// context.currentLength = 0;
1725 		sbf.append(System.getProperty("line.separator"));
1726 		line++;
1727 		return writeTabs();
1728 	}
1729 
1730 	public DefaultJavaPrettyPrinter writeTabs() {
1731 		// context.currentLength = 0;
1732 		for (int i = 0; i < context.nbTabs; i++) {
1733 			// context.currentLength += TAB.length();
1734 			if (env.isUsingTabulations()) {
1735 				sbf.append("\t");
1736 			} else {
1737 				for (int j = 0; j < env.getTabulationSize(); j++) {
1738 					sbf.append(" ");
1739 				}
1740 			}
1741 		}
1742 		return this;
1743 	}
1744 
1745 	/**
1746 	 * Writes a binary operator.
1747 	 */
1748 	public DefaultJavaPrettyPrinter writeOperator(BinaryOperatorKind o) {
1749 		switch (o) {
1750 		case OR:
1751 			write("||");
1752 			break;
1753 		case AND:
1754 			write("&&");
1755 			break;
1756 		case BITOR:
1757 			write("|");
1758 			break;
1759 		case BITXOR:
1760 			write("^");
1761 			break;
1762 		case BITAND:
1763 			write("&");
1764 			break;
1765 		case EQ:
1766 			write("==");
1767 			break;
1768 		case NE:
1769 			write("!=");
1770 			break;
1771 		case LT:
1772 			write("<");
1773 			break;
1774 		case GT:
1775 			write(">");
1776 			break;
1777 		case LE:
1778 			write("<=");
1779 			break;
1780 		case GE:
1781 			write(">=");
1782 			break;
1783 		case SL:
1784 			write("<<");
1785 			break;
1786 		case SR:
1787 			write(">>");
1788 			break;
1789 		case USR:
1790 			write(">>>");
1791 			break;
1792 		case PLUS:
1793 			write("+");
1794 			break;
1795 		case MINUS:
1796 			write("-");
1797 			break;
1798 		case MUL:
1799 			write("*");
1800 			break;
1801 		case DIV:
1802 			write("/");
1803 			break;
1804 		case MOD:
1805 			write("%");
1806 			break;
1807 		case INSTANCEOF:
1808 			write("instanceof");
1809 			break;
1810 		}
1811 		return this;
1812 	}
1813 
1814 	/**
1815 	 * Write some parameters.
1816 	 */
1817 	protected void writeParameters(Collection<CtTypeReference<?>> params) {
1818 		if (params.size() > 0) {
1819 			write("(");
1820 			for (CtTypeReference<?> param : params) {
1821 				scan(param);
1822 				write(", ");
1823 			}
1824 			removeLastChar();
1825 			write(")");
1826 		}
1827 	}
1828 
1829 	/**
1830 	 * Writes a statement.
1831 	 */
1832 	protected void writeStatement(CtStatement e) {
1833 		scan(e);
1834 		if (!((e instanceof CtBlock) || (e instanceof CtIf)
1835 				|| (e instanceof CtFor) || (e instanceof CtForEach)
1836 				|| (e instanceof CtWhile) || (e instanceof CtTry)
1837 				|| (e instanceof CtSwitch) || (e instanceof CtSynchronized))) {
1838 			write(";");
1839 		}
1840 	}
1841 
1842 	public <T> void visitCtCodeSnippetExpression(
1843 			CtCodeSnippetExpression<T> expression) {
1844 		write(expression.getValue());
1845 	}
1846 
1847 	public void visitCtCodeSnippetStatement(CtCodeSnippetStatement statement) {
1848 		write(statement.getValue());
1849 	}
1850 
1851 	private CompilationUnit sourceCompilationUnit;
1852 
1853 	public void calculate(CompilationUnit sourceCompilationUnit,
1854 			List<CtSimpleType<?>> types) {
1855 		this.sourceCompilationUnit = sourceCompilationUnit;
1856 		for (CtSimpleType<?> t : types) {
1857 			makeImports(t);
1858 		}
1859 		writeHeader(types);
1860 		for (CtSimpleType<?> t : types) {
1861 			scan(t);
1862 			writeln().writeln();
1863 		}
1864 	}
1865 
1866 	public Map<Integer, Integer> getLineNumberMapping() {
1867 		return lineNumberMapping;
1868 	}
1869 }