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