1 /* 2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 supported API. 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_8) 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 SimpleElementVisitor7<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 SimpleElementVisitor7<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 // Handle any enum constants specially before other entities. 232 List<Element> enumConstants = new ArrayList<Element>(); 233 for(Element element : enclosedElements) { 234 if (element.getKind() == ENUM_CONSTANT) 235 enumConstants.add(element); 236 } 237 if (!enumConstants.isEmpty()) { 238 int i; 239 for(i = 0; i < enumConstants.size()-1; i++) { 240 this.visit(enumConstants.get(i), true); 241 writer.print(","); 242 } 243 this.visit(enumConstants.get(i), true); 244 writer.println(";\n"); 245 246 enclosedElements.removeAll(enumConstants); 247 } 248 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(Parameterizable e, 369 boolean pad) { 370 List<? extends TypeParameterElement> typeParams = e.getTypeParameters(); 371 if (typeParams.size() > 0) { 372 writer.print("<"); 373 374 boolean first = true; 375 for(TypeParameterElement tpe: typeParams) { 376 if (!first) 377 writer.print(", "); 378 printAnnotationsInline(tpe); 379 writer.print(tpe.toString()); 380 first = false; 381 } 382 383 writer.print(">"); 384 if (pad) 385 writer.print(" "); 386 } 387 } 388 389 private void printAnnotationsInline(Element e) { 390 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 391 for(AnnotationMirror annotationMirror : annots) { 392 writer.print(annotationMirror); 393 writer.print(" "); 394 } 395 } 396 397 private void printAnnotations(Element e) { 398 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 399 for(AnnotationMirror annotationMirror : annots) { 400 indent(); 401 writer.println(annotationMirror); 402 } 403 } 404 405 // TODO: Refactor 406 private void printParameters(ExecutableElement e) { 407 List<? extends VariableElement> parameters = e.getParameters(); 408 int size = parameters.size(); 409 410 switch (size) { 411 case 0: 412 break; 413 414 case 1: 415 for(VariableElement parameter: parameters) { 416 printModifiers(parameter); 417 418 if (e.isVarArgs() ) { 419 TypeMirror tm = parameter.asType(); 420 if (tm.getKind() != TypeKind.ARRAY) 421 throw new AssertionError("Var-args parameter is not an array type: " + tm); 422 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 423 writer.print("..."); 424 } else 425 writer.print(parameter.asType()); 426 writer.print(" " + parameter.getSimpleName()); 427 } 428 break; 429 430 default: 431 { 432 int i = 1; 433 for(VariableElement parameter: parameters) { 434 if (i == 2) 435 indentation++; 436 437 if (i > 1) 438 indent(); 439 440 printModifiers(parameter); 441 442 if (i == size && e.isVarArgs() ) { 443 TypeMirror tm = parameter.asType(); 444 if (tm.getKind() != TypeKind.ARRAY) 445 throw new AssertionError("Var-args parameter is not an array type: " + tm); 446 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 447 448 writer.print("..."); 449 } else 450 writer.print(parameter.asType()); 451 writer.print(" " + parameter.getSimpleName()); 452 453 if (i < size) 454 writer.println(","); 455 456 i++; 457 } 458 459 if (parameters.size() >= 2) 460 indentation--; 461 } 462 break; 463 } 464 } 465 466 private void printInterfaces(TypeElement e) { 467 ElementKind kind = e.getKind(); 468 469 if(kind != ANNOTATION_TYPE) { 470 List<? extends TypeMirror> interfaces = e.getInterfaces(); 471 if (interfaces.size() > 0) { 472 writer.print((kind.isClass() ? " implements" : " extends")); 473 474 boolean first = true; 475 for(TypeMirror interf: interfaces) { 476 if (!first) 477 writer.print(","); 478 writer.print(" "); 479 writer.print(interf.toString()); 480 first = false; 481 } 482 } 483 } 484 } 485 486 private void printThrows(ExecutableElement e) { 487 List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); 488 final int size = thrownTypes.size(); 489 if (size != 0) { 490 writer.print(" throws"); 491 492 int i = 1; 493 for(TypeMirror thrownType: thrownTypes) { 494 if (i == 1) 495 writer.print(" "); 496 497 if (i == 2) 498 indentation++; 499 500 if (i >= 2) 501 indent(); 502 503 writer.print(thrownType); 504 505 if (i != size) 506 writer.println(", "); 507 508 i++; 509 } 510 511 if (size >= 2) 512 indentation--; 513 } 514 } 515 516 private static final String [] spaces = { 517 "", 518 " ", 519 " ", 520 " ", 521 " ", 522 " ", 523 " ", 524 " ", 525 " ", 526 " ", 527 " " 528 }; 529 530 private void indent() { 531 int indentation = this.indentation; 532 if (indentation < 0) 533 return; 534 final int maxIndex = spaces.length - 1; 535 536 while (indentation > maxIndex) { 537 writer.print(spaces[maxIndex]); 538 indentation -= maxIndex; 539 } 540 writer.print(spaces[indentation]); 541 } 542 543 } 544 }