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 // TODO: Change to version 7 based visitors when available 52 @SupportedSourceVersion(SourceVersion.RELEASE_7) 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 SimpleElementVisitor7<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 SimpleElementVisitor7<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, true); 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, false); 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 // Handle any enum constants specially before other entities. 233 List<Element> enumConstants = new ArrayList<Element>(); 234 for(Element element : enclosedElements) { 235 if (element.getKind() == ENUM_CONSTANT) 236 enumConstants.add(element); 237 } 238 if (!enumConstants.isEmpty()) { 239 int i; 240 for(i = 0; i < enumConstants.size()-1; i++) { 241 this.visit(enumConstants.get(i), true); 242 writer.print(","); 243 } 244 this.visit(enumConstants.get(i), true); 245 writer.println(";\n"); 246 247 enclosedElements.removeAll(enumConstants); 248 } 249 250 for(Element element : enclosedElements) 251 this.visit(element); 252 } else { 253 for(Element element : e.getEnclosedElements()) 254 this.visit(element); 255 } 256 257 indentation--; 258 indent(); 259 writer.println("}"); 260 return this; 261 } 262 263 @Override 264 public PrintingElementVisitor visitVariable(VariableElement e, Boolean newLine) { 265 ElementKind kind = e.getKind(); 266 defaultAction(e, newLine); 267 268 if (kind == ENUM_CONSTANT) 269 writer.print(e.getSimpleName()); 270 else { 271 writer.print(e.asType().toString() + " " + e.getSimpleName() ); 272 Object constantValue = e.getConstantValue(); 273 if (constantValue != null) { 274 writer.print(" = "); 275 writer.print(elementUtils.getConstantExpression(constantValue)); 276 } 277 writer.println(";"); 278 } 279 return this; 280 } 281 282 @Override 283 public PrintingElementVisitor visitTypeParameter(TypeParameterElement e, Boolean p) { 284 writer.print(e.getSimpleName()); 285 return this; 286 } 287 288 // Should we do more here? 289 @Override 290 public PrintingElementVisitor visitPackage(PackageElement e, Boolean p) { 291 defaultAction(e, false); 292 if (!e.isUnnamed()) 293 writer.println("package " + e.getQualifiedName() + ";"); 294 else 295 writer.println("// Unnamed package"); 296 return this; 297 } 298 299 public void flush() { 300 writer.flush(); 301 } 302 303 private void printDocComment(Element e) { 304 String docComment = elementUtils.getDocComment(e); 305 306 if (docComment != null) { 307 // Break comment into lines 308 java.util.StringTokenizer st = new StringTokenizer(docComment, 309 "\n\r"); 310 indent(); 311 writer.println("/**"); 312 313 while(st.hasMoreTokens()) { 314 indent(); 315 writer.print(" *"); 316 writer.println(st.nextToken()); 317 } 318 319 indent(); 320 writer.println(" */"); 321 } 322 } 323 324 private void printModifiers(Element e) { 325 ElementKind kind = e.getKind(); 326 if (kind == PARAMETER) { 327 printAnnotationsInline(e); 328 } else { 329 printAnnotations(e); 330 indent(); 331 } 332 333 if (kind == ENUM_CONSTANT) 334 return; 335 336 Set<Modifier> modifiers = new LinkedHashSet<Modifier>(); 337 modifiers.addAll(e.getModifiers()); 338 339 switch (kind) { 340 case ANNOTATION_TYPE: 341 case INTERFACE: 342 modifiers.remove(Modifier.ABSTRACT); 343 break; 344 345 case ENUM: 346 modifiers.remove(Modifier.FINAL); 347 modifiers.remove(Modifier.ABSTRACT); 348 break; 349 350 case METHOD: 351 case FIELD: 352 Element enclosingElement = e.getEnclosingElement(); 353 if (enclosingElement != null && 354 enclosingElement.getKind().isInterface()) { 355 modifiers.remove(Modifier.PUBLIC); 356 modifiers.remove(Modifier.ABSTRACT); // only for methods 357 modifiers.remove(Modifier.STATIC); // only for fields 358 modifiers.remove(Modifier.FINAL); // only for fields 359 } 360 break; 361 362 } 363 364 for(Modifier m: modifiers) { 365 writer.print(m.toString() + " "); 366 } 367 } 368 369 private void printFormalTypeParameters(Parameterizable e, 370 boolean pad) { 371 List<? extends TypeParameterElement> typeParams = e.getTypeParameters(); 372 if (typeParams.size() > 0) { 373 writer.print("<"); 374 375 boolean first = true; 376 for(TypeParameterElement tpe: typeParams) { 377 if (!first) 378 writer.print(", "); 379 printAnnotationsInline(tpe); 380 writer.print(tpe.toString()); 381 first = false; 382 } 383 384 writer.print(">"); 385 if (pad) 386 writer.print(" "); 387 } 388 } 389 390 private void printAnnotationsInline(Element e) { 391 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 392 for(AnnotationMirror annotationMirror : annots) { 393 writer.print(annotationMirror); 394 writer.print(" "); 395 } 396 } 397 398 private void printAnnotations(Element e) { 399 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 400 for(AnnotationMirror annotationMirror : annots) { 401 indent(); 402 writer.println(annotationMirror); 403 } 404 } 405 406 // TODO: Refactor 407 private void printParameters(ExecutableElement e) { 408 List<? extends VariableElement> parameters = e.getParameters(); 409 int size = parameters.size(); 410 411 switch (size) { 412 case 0: 413 break; 414 415 case 1: 416 for(VariableElement parameter: parameters) { 417 printModifiers(parameter); 418 419 if (e.isVarArgs() ) { 420 TypeMirror tm = parameter.asType(); 421 if (tm.getKind() != TypeKind.ARRAY) 422 throw new AssertionError("Var-args parameter is not an array type: " + tm); 423 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 424 writer.print("..."); 425 } else 426 writer.print(parameter.asType()); 427 writer.print(" " + parameter.getSimpleName()); 428 } 429 break; 430 431 default: 432 { 433 int i = 1; 434 for(VariableElement parameter: parameters) { 435 if (i == 2) 436 indentation++; 437 438 if (i > 1) 439 indent(); 440 441 printModifiers(parameter); 442 443 if (i == size && e.isVarArgs() ) { 444 TypeMirror tm = parameter.asType(); 445 if (tm.getKind() != TypeKind.ARRAY) 446 throw new AssertionError("Var-args parameter is not an array type: " + tm); 447 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 448 449 writer.print("..."); 450 } else 451 writer.print(parameter.asType()); 452 writer.print(" " + parameter.getSimpleName()); 453 454 if (i < size) 455 writer.println(","); 456 457 i++; 458 } 459 460 if (parameters.size() >= 2) 461 indentation--; 462 } 463 break; 464 } 465 } 466 467 private void printInterfaces(TypeElement e) { 468 ElementKind kind = e.getKind(); 469 470 if(kind != ANNOTATION_TYPE) { 471 List<? extends TypeMirror> interfaces = e.getInterfaces(); 472 if (interfaces.size() > 0) { 473 writer.print((kind.isClass() ? " implements" : " extends")); 474 475 boolean first = true; 476 for(TypeMirror interf: interfaces) { 477 if (!first) 478 writer.print(","); 479 writer.print(" "); 480 writer.print(interf.toString()); 481 first = false; 482 } 483 } 484 } 485 } 486 487 private void printThrows(ExecutableElement e) { 488 List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); 489 final int size = thrownTypes.size(); 490 if (size != 0) { 491 writer.print(" throws"); 492 493 int i = 1; 494 for(TypeMirror thrownType: thrownTypes) { 495 if (i == 1) 496 writer.print(" "); 497 498 if (i == 2) 499 indentation++; 500 501 if (i >= 2) 502 indent(); 503 504 writer.print(thrownType); 505 506 if (i != size) 507 writer.println(", "); 508 509 i++; 510 } 511 512 if (size >= 2) 513 indentation--; 514 } 515 } 516 517 private static final String [] spaces = { 518 "", 519 " ", 520 " ", 521 " ", 522 " ", 523 " ", 524 " ", 525 " ", 526 " ", 527 " ", 528 " " 529 }; 530 531 private void indent() { 532 int indentation = this.indentation; 533 if (indentation < 0) 534 return; 535 final int maxIndex = spaces.length - 1; 536 537 while (indentation > maxIndex) { 538 writer.print(spaces[maxIndex]); 539 indentation -= maxIndex; 540 } 541 writer.print(spaces[indentation]); 542 } 543 544 } 545 }