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