1 | /* |
2 | * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Sun designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Sun in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
23 | * have any questions. |
24 | */ |
25 | |
26 | package com.sun.tools.javac.processing; |
27 | |
28 | import javax.annotation.processing.*; |
29 | import javax.lang.model.*; |
30 | import javax.lang.model.element.*; |
31 | import static javax.lang.model.element.ElementKind.*; |
32 | import static javax.lang.model.element.NestingKind.*; |
33 | import javax.lang.model.type.*; |
34 | import javax.lang.model.util.*; |
35 | import static javax.lang.model.util.ElementFilter.*; |
36 | |
37 | import java.io.PrintWriter; |
38 | import java.io.Writer; |
39 | import java.util.*; |
40 | |
41 | /** |
42 | * A processor which prints out elements. Used to implement the |
43 | * -Xprint option; the included visitor class is used to implement |
44 | * Elements.printElements. |
45 | * |
46 | * <p><b>This is NOT part of any API supported by Sun Microsystems. |
47 | * If you write code that depends on this, you do so at your own risk. |
48 | * This code and its internal interfaces are subject to change or |
49 | * deletion without notice.</b> |
50 | */ |
51 | @SupportedAnnotationTypes("*") |
52 | @SupportedSourceVersion(SourceVersion.RELEASE_6) |
53 | public class PrintingProcessor extends AbstractProcessor { |
54 | PrintWriter writer; |
55 | |
56 | public PrintingProcessor() { |
57 | super(); |
58 | writer = new PrintWriter(System.out); |
59 | } |
60 | |
61 | public void setWriter(Writer w) { |
62 | writer = new PrintWriter(w); |
63 | } |
64 | |
65 | @Override |
66 | public boolean process(Set<? extends TypeElement> tes, |
67 | RoundEnvironment renv) { |
68 | |
69 | for(Element element : renv.getRootElements()) { |
70 | print(element); |
71 | } |
72 | |
73 | // Just print the elements, nothing more to do. |
74 | return true; |
75 | } |
76 | |
77 | void print(Element element) { |
78 | new PrintingElementVisitor(writer, processingEnv.getElementUtils()). |
79 | visit(element).flush(); |
80 | } |
81 | |
82 | /** |
83 | * Used for the -Xprint option and called by Elements.printElements |
84 | */ |
85 | public static class PrintingElementVisitor |
86 | extends SimpleElementVisitor6<PrintingElementVisitor, Boolean> { |
87 | int indentation; // Indentation level; |
88 | final PrintWriter writer; |
89 | final Elements elementUtils; |
90 | |
91 | public PrintingElementVisitor(Writer w, Elements elementUtils) { |
92 | super(); |
93 | this.writer = new PrintWriter(w); |
94 | this.elementUtils = elementUtils; |
95 | indentation = 0; |
96 | } |
97 | |
98 | @Override |
99 | protected PrintingElementVisitor defaultAction(Element e, Boolean newLine) { |
100 | if (newLine != null && newLine) |
101 | writer.println(); |
102 | printDocComment(e); |
103 | printModifiers(e); |
104 | return this; |
105 | } |
106 | |
107 | @Override |
108 | public PrintingElementVisitor visitExecutable(ExecutableElement e, Boolean p) { |
109 | ElementKind kind = e.getKind(); |
110 | |
111 | if (kind != STATIC_INIT && |
112 | kind != INSTANCE_INIT) { |
113 | Element enclosing = e.getEnclosingElement(); |
114 | |
115 | // Don't print out the constructor of an anonymous class |
116 | if (kind == CONSTRUCTOR && |
117 | enclosing != null && |
118 | NestingKind.ANONYMOUS == |
119 | // Use an anonymous class to determine anonymity! |
120 | (new SimpleElementVisitor6<NestingKind, Void>() { |
121 | @Override |
122 | public NestingKind visitType(TypeElement e, Void p) { |
123 | return e.getNestingKind(); |
124 | } |
125 | }).visit(enclosing)) |
126 | return this; |
127 | |
128 | defaultAction(e, true); |
129 | printFormalTypeParameters(e); |
130 | |
131 | switch(kind) { |
132 | case CONSTRUCTOR: |
133 | // Print out simple name of the class |
134 | writer.print(e.getEnclosingElement().getSimpleName()); |
135 | break; |
136 | |
137 | case METHOD: |
138 | writer.print(e.getReturnType().toString()); |
139 | writer.print(" "); |
140 | writer.print(e.getSimpleName().toString()); |
141 | break; |
142 | } |
143 | |
144 | writer.print("("); |
145 | printParameters(e); |
146 | writer.print(")"); |
147 | AnnotationValue defaultValue = e.getDefaultValue(); |
148 | if (defaultValue != null) |
149 | writer.print(" default " + defaultValue); |
150 | |
151 | printThrows(e); |
152 | writer.println(";"); |
153 | } |
154 | return this; |
155 | } |
156 | |
157 | |
158 | @Override |
159 | public PrintingElementVisitor visitType(TypeElement e, Boolean p) { |
160 | ElementKind kind = e.getKind(); |
161 | NestingKind nestingKind = e.getNestingKind(); |
162 | |
163 | if (NestingKind.ANONYMOUS == nestingKind) { |
164 | // Print out an anonymous class in the style of a |
165 | // class instance creation expression rather than a |
166 | // class declaration. |
167 | writer.print("new "); |
168 | |
169 | // If the anonymous class implements an interface |
170 | // print that name, otherwise print the superclass. |
171 | List<? extends TypeMirror> interfaces = e.getInterfaces(); |
172 | if (!interfaces.isEmpty()) |
173 | writer.print(interfaces.get(0)); |
174 | else |
175 | writer.print(e.getSuperclass()); |
176 | |
177 | writer.print("("); |
178 | // Anonymous classes that implement an interface can't |
179 | // have any constructor arguments. |
180 | if (interfaces.isEmpty()) { |
181 | // Print out the parameter list from the sole |
182 | // constructor. For now, don't try to elide any |
183 | // synthetic parameters by determining if the |
184 | // anonymous class is in a static context, etc. |
185 | List<? extends ExecutableElement> constructors = |
186 | ElementFilter.constructorsIn(e.getEnclosedElements()); |
187 | |
188 | if (!constructors.isEmpty()) |
189 | printParameters(constructors.get(0)); |
190 | } |
191 | writer.print(")"); |
192 | } else { |
193 | if (nestingKind == TOP_LEVEL) { |
194 | PackageElement pkg = elementUtils.getPackageOf(e); |
195 | if (!pkg.isUnnamed()) |
196 | writer.print("package " + pkg.getQualifiedName() + ";\n"); |
197 | } |
198 | |
199 | defaultAction(e, true); |
200 | |
201 | switch(kind) { |
202 | case ANNOTATION_TYPE: |
203 | writer.print("@interface"); |
204 | break; |
205 | default: |
206 | writer.print(kind.toString().toLowerCase()); |
207 | } |
208 | writer.print(" "); |
209 | writer.print(e.getSimpleName()); |
210 | |
211 | printFormalTypeParameters(e); |
212 | |
213 | // Print superclass information if informative |
214 | if (kind == CLASS) { |
215 | TypeMirror supertype = e.getSuperclass(); |
216 | if (supertype.getKind() != TypeKind.NONE) { |
217 | TypeElement e2 = (TypeElement) |
218 | ((DeclaredType) supertype).asElement(); |
219 | if (e2.getSuperclass().getKind() != TypeKind.NONE) |
220 | writer.print(" extends " + supertype); |
221 | } |
222 | } |
223 | |
224 | printInterfaces(e); |
225 | } |
226 | writer.println(" {"); |
227 | indentation++; |
228 | |
229 | if (kind == ENUM) { |
230 | List<Element> enclosedElements = |
231 | new ArrayList<Element>(e.getEnclosedElements()); |
232 | List<Element> enumConstants = new ArrayList<Element>(); |
233 | for(Element element : enclosedElements) { |
234 | if (element.getKind() == ENUM_CONSTANT) |
235 | enumConstants.add(element); |
236 | } |
237 | |
238 | int i; |
239 | for(i = 0; i < enumConstants.size()-1; i++) { |
240 | this.visit(enumConstants.get(i), true); |
241 | writer.print(","); |
242 | } |
243 | if (i >= 0 ) { |
244 | this.visit(enumConstants.get(i), true); |
245 | writer.print(";"); |
246 | } |
247 | |
248 | enclosedElements.removeAll(enumConstants); |
249 | for(Element element : enclosedElements) |
250 | this.visit(element); |
251 | } else { |
252 | for(Element element : e.getEnclosedElements()) |
253 | this.visit(element); |
254 | } |
255 | |
256 | indentation--; |
257 | indent(); |
258 | writer.println("}"); |
259 | return this; |
260 | } |
261 | |
262 | @Override |
263 | public PrintingElementVisitor visitVariable(VariableElement e, Boolean newLine) { |
264 | ElementKind kind = e.getKind(); |
265 | defaultAction(e, newLine); |
266 | |
267 | if (kind == ENUM_CONSTANT) |
268 | writer.print(e.getSimpleName()); |
269 | else { |
270 | writer.print(e.asType().toString() + " " + e.getSimpleName() ); |
271 | Object constantValue = e.getConstantValue(); |
272 | if (constantValue != null) { |
273 | writer.print(" = "); |
274 | writer.print(elementUtils.getConstantExpression(constantValue)); |
275 | } |
276 | writer.println(";"); |
277 | } |
278 | return this; |
279 | } |
280 | |
281 | @Override |
282 | public PrintingElementVisitor visitTypeParameter(TypeParameterElement e, Boolean p) { |
283 | writer.print(e.getSimpleName()); |
284 | return this; |
285 | } |
286 | |
287 | // Should we do more here? |
288 | @Override |
289 | public PrintingElementVisitor visitPackage(PackageElement e, Boolean p) { |
290 | defaultAction(e, false); |
291 | if (!e.isUnnamed()) |
292 | writer.println("package " + e.getQualifiedName() + ";"); |
293 | else |
294 | writer.println("// Unnamed package"); |
295 | return this; |
296 | } |
297 | |
298 | public void flush() { |
299 | writer.flush(); |
300 | } |
301 | |
302 | private void printDocComment(Element e) { |
303 | String docComment = elementUtils.getDocComment(e); |
304 | |
305 | if (docComment != null) { |
306 | // Break comment into lines |
307 | java.util.StringTokenizer st = new StringTokenizer(docComment, |
308 | "\n\r"); |
309 | indent(); |
310 | writer.println("/**"); |
311 | |
312 | while(st.hasMoreTokens()) { |
313 | indent(); |
314 | writer.print(" *"); |
315 | writer.println(st.nextToken()); |
316 | } |
317 | |
318 | indent(); |
319 | writer.println(" */"); |
320 | } |
321 | } |
322 | |
323 | private void printModifiers(Element e) { |
324 | ElementKind kind = e.getKind(); |
325 | if (kind == PARAMETER) { |
326 | printAnnotationsInline(e); |
327 | } else { |
328 | printAnnotations(e); |
329 | indent(); |
330 | } |
331 | |
332 | if (kind == ENUM_CONSTANT) |
333 | return; |
334 | |
335 | Set<Modifier> modifiers = new LinkedHashSet<Modifier>(); |
336 | modifiers.addAll(e.getModifiers()); |
337 | |
338 | switch (kind) { |
339 | case ANNOTATION_TYPE: |
340 | case INTERFACE: |
341 | modifiers.remove(Modifier.ABSTRACT); |
342 | break; |
343 | |
344 | case ENUM: |
345 | modifiers.remove(Modifier.FINAL); |
346 | modifiers.remove(Modifier.ABSTRACT); |
347 | break; |
348 | |
349 | case METHOD: |
350 | case FIELD: |
351 | Element enclosingElement = e.getEnclosingElement(); |
352 | if (enclosingElement != null && |
353 | enclosingElement.getKind().isInterface()) { |
354 | modifiers.remove(Modifier.PUBLIC); |
355 | modifiers.remove(Modifier.ABSTRACT); // only for methods |
356 | modifiers.remove(Modifier.STATIC); // only for fields |
357 | modifiers.remove(Modifier.FINAL); // only for fields |
358 | } |
359 | break; |
360 | |
361 | } |
362 | |
363 | for(Modifier m: modifiers) { |
364 | writer.print(m.toString() + " "); |
365 | } |
366 | } |
367 | |
368 | private void printFormalTypeParameters(ExecutableElement executable) { |
369 | printFormalTypeParameters(executable.getTypeParameters(), true); |
370 | } |
371 | |
372 | private void printFormalTypeParameters(TypeElement type) { |
373 | printFormalTypeParameters(type.getTypeParameters(), false); |
374 | } |
375 | |
376 | private void printFormalTypeParameters(List<? extends TypeParameterElement> typeParams, |
377 | boolean pad) { |
378 | if (typeParams.size() > 0) { |
379 | writer.print("<"); |
380 | |
381 | boolean first = true; |
382 | for(TypeParameterElement tpe: typeParams) { |
383 | if (!first) |
384 | writer.print(", "); |
385 | writer.print(tpe.toString()); |
386 | first = false; |
387 | } |
388 | |
389 | writer.print(">"); |
390 | if (pad) |
391 | writer.print(" "); |
392 | } |
393 | } |
394 | |
395 | private void printAnnotationsInline(Element e) { |
396 | List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); |
397 | for(AnnotationMirror annotationMirror : annots) { |
398 | writer.print(annotationMirror); |
399 | writer.print(" "); |
400 | } |
401 | } |
402 | |
403 | private void printAnnotations(Element e) { |
404 | List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); |
405 | for(AnnotationMirror annotationMirror : annots) { |
406 | indent(); |
407 | writer.println(annotationMirror); |
408 | } |
409 | } |
410 | |
411 | // TODO: Refactor |
412 | private void printParameters(ExecutableElement e) { |
413 | List<? extends VariableElement> parameters = e.getParameters(); |
414 | int size = parameters.size(); |
415 | |
416 | switch (size) { |
417 | case 0: |
418 | break; |
419 | |
420 | case 1: |
421 | for(VariableElement parameter: parameters) { |
422 | printModifiers(parameter); |
423 | |
424 | if (e.isVarArgs() ) { |
425 | TypeMirror tm = parameter.asType(); |
426 | if (tm.getKind() != TypeKind.ARRAY) |
427 | throw new AssertionError("Var-args parameter is not an array type: " + tm); |
428 | writer.print((ArrayType.class.cast(tm)).getComponentType() ); |
429 | writer.print("..."); |
430 | } else |
431 | writer.print(parameter.asType()); |
432 | writer.print(" " + parameter.getSimpleName()); |
433 | } |
434 | break; |
435 | |
436 | default: |
437 | { |
438 | int i = 1; |
439 | for(VariableElement parameter: parameters) { |
440 | if (i == 2) |
441 | indentation++; |
442 | |
443 | if (i > 1) |
444 | indent(); |
445 | |
446 | printModifiers(parameter); |
447 | |
448 | if (i == size && e.isVarArgs() ) { |
449 | TypeMirror tm = parameter.asType(); |
450 | if (tm.getKind() != TypeKind.ARRAY) |
451 | throw new AssertionError("Var-args parameter is not an array type: " + tm); |
452 | writer.print((ArrayType.class.cast(tm)).getComponentType() ); |
453 | |
454 | writer.print("..."); |
455 | } else |
456 | writer.print(parameter.asType()); |
457 | writer.print(" " + parameter.getSimpleName()); |
458 | |
459 | if (i < size) |
460 | writer.println(","); |
461 | |
462 | i++; |
463 | } |
464 | |
465 | if (parameters.size() >= 2) |
466 | indentation--; |
467 | } |
468 | break; |
469 | } |
470 | } |
471 | |
472 | private void printInterfaces(TypeElement e) { |
473 | ElementKind kind = e.getKind(); |
474 | |
475 | if(kind != ANNOTATION_TYPE) { |
476 | List<? extends TypeMirror> interfaces = e.getInterfaces(); |
477 | if (interfaces.size() > 0) { |
478 | writer.print((kind.isClass() ? " implements" : " extends")); |
479 | |
480 | boolean first = true; |
481 | for(TypeMirror interf: interfaces) { |
482 | if (!first) |
483 | writer.print(","); |
484 | writer.print(" "); |
485 | writer.print(interf.toString()); |
486 | first = false; |
487 | } |
488 | } |
489 | } |
490 | } |
491 | |
492 | private void printThrows(ExecutableElement e) { |
493 | List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); |
494 | final int size = thrownTypes.size(); |
495 | if (size != 0) { |
496 | writer.print(" throws"); |
497 | |
498 | int i = 1; |
499 | for(TypeMirror thrownType: thrownTypes) { |
500 | if (i == 1) |
501 | writer.print(" "); |
502 | |
503 | if (i == 2) |
504 | indentation++; |
505 | |
506 | if (i >= 2) |
507 | indent(); |
508 | |
509 | writer.print(thrownType); |
510 | |
511 | if (i != size) |
512 | writer.println(", "); |
513 | |
514 | i++; |
515 | } |
516 | |
517 | if (size >= 2) |
518 | indentation--; |
519 | } |
520 | } |
521 | |
522 | private static final String [] spaces = { |
523 | "", |
524 | " ", |
525 | " ", |
526 | " ", |
527 | " ", |
528 | " ", |
529 | " ", |
530 | " ", |
531 | " ", |
532 | " ", |
533 | " " |
534 | }; |
535 | |
536 | private void indent() { |
537 | int indentation = this.indentation; |
538 | if (indentation < 0) |
539 | return; |
540 | final int maxIndex = spaces.length - 1; |
541 | |
542 | while (indentation > maxIndex) { |
543 | writer.print(spaces[maxIndex]); |
544 | indentation -= maxIndex; |
545 | } |
546 | writer.print(spaces[indentation]); |
547 | } |
548 | |
549 | } |
550 | } |