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 (new PrintDirective(writer)).visit(directive); 327 writer.println(";"); 328 } 329 330 private static class PrintDirective implements ModuleElement.DirectiveVisitor<Void, Void> { 331 private final PrintWriter writer; 332 333 PrintDirective(PrintWriter writer) { 334 this.writer = writer; 335 } 336 337 @Override @DefinedBy(Api.LANGUAGE_MODEL) 338 public Void visitExports(ExportsDirective d, Void p) { 339 // "exports package-name [to module-name-list]" 340 writer.print("exports "); 341 writer.print(d.getPackage().getQualifiedName()); 342 printModuleList(d.getTargetModules()); 343 return null; 344 } 345 346 @Override @DefinedBy(Api.LANGUAGE_MODEL) 347 public Void visitOpens(OpensDirective d, Void p) { 348 // opens package-name [to module-name-list] 349 writer.print("opens "); 350 writer.print(d.getPackage().getQualifiedName()); 351 printModuleList(d.getTargetModules()); 352 return null; 353 } 354 355 @Override @DefinedBy(Api.LANGUAGE_MODEL) 356 public Void visitProvides(ProvidesDirective d, Void p) { 357 // provides service-name with implementation-name 358 writer.print("provides "); 359 writer.print(d.getService().getQualifiedName()); 360 writer.print(" with "); 361 printNameableList(d.getImplementations()); 362 return null; 363 } 364 365 @Override @DefinedBy(Api.LANGUAGE_MODEL) 366 public Void visitRequires(RequiresDirective d, Void p) { 367 // requires (static|transitive)* module-name 368 writer.print("requires "); 369 if (d.isStatic()) 370 writer.print("static "); 371 if (d.isTransitive()) 372 writer.print("transitive "); 373 writer.print(d.getDependency().getQualifiedName()); 374 return null; 375 } 376 377 @Override @DefinedBy(Api.LANGUAGE_MODEL) 378 public Void visitUses(UsesDirective d, Void p) { 379 // uses service-name 380 writer.print("uses "); 381 writer.print(d.getService().getQualifiedName()); 382 return null; 383 } 384 385 private void printModuleList(List<? extends ModuleElement> modules) { 386 if (modules != null) { 387 writer.print(" to "); 388 printNameableList(modules); 389 } 390 } 391 392 private void printNameableList(List<? extends QualifiedNameable> nameables) { 393 writer.print(nameables.stream(). 394 map(QualifiedNameable::getQualifiedName). 395 collect(Collectors.joining(", "))); 396 } 397 } 398 399 public void flush() { 400 writer.flush(); 401 } 402 403 private void printDocComment(Element e) { 404 String docComment = elementUtils.getDocComment(e); 405 406 if (docComment != null) { 407 // Break comment into lines 408 java.util.StringTokenizer st = new StringTokenizer(docComment, 409 "\n\r"); 410 indent(); 411 writer.println("/**"); 412 413 while(st.hasMoreTokens()) { 414 indent(); 415 writer.print(" *"); 416 writer.println(st.nextToken()); 417 } 418 419 indent(); 420 writer.println(" */"); 421 } 422 } 423 424 private void printModifiers(Element e) { 425 ElementKind kind = e.getKind(); 426 if (kind == PARAMETER) { 427 printAnnotationsInline(e); 428 } else { 429 printAnnotations(e); 430 indent(); 431 } 432 433 if (kind == ENUM_CONSTANT) 434 return; 435 436 Set<Modifier> modifiers = new LinkedHashSet<>(); 437 modifiers.addAll(e.getModifiers()); 438 439 switch (kind) { 440 case ANNOTATION_TYPE: 441 case INTERFACE: 442 modifiers.remove(Modifier.ABSTRACT); 443 break; 444 445 case ENUM: 446 modifiers.remove(Modifier.FINAL); 447 modifiers.remove(Modifier.ABSTRACT); 448 break; 449 450 case METHOD: 451 case FIELD: 452 Element enclosingElement = e.getEnclosingElement(); 453 if (enclosingElement != null && 454 enclosingElement.getKind().isInterface()) { 455 modifiers.remove(Modifier.PUBLIC); 456 modifiers.remove(Modifier.ABSTRACT); // only for methods 457 modifiers.remove(Modifier.STATIC); // only for fields 458 modifiers.remove(Modifier.FINAL); // only for fields 459 } 460 break; 461 462 } 463 464 for(Modifier m: modifiers) { 465 writer.print(m.toString() + " "); 466 } 467 } 468 469 private void printFormalTypeParameters(Parameterizable e, 470 boolean pad) { 471 List<? extends TypeParameterElement> typeParams = e.getTypeParameters(); 472 if (typeParams.size() > 0) { 473 writer.print("<"); 474 475 boolean first = true; 476 for(TypeParameterElement tpe: typeParams) { 477 if (!first) 478 writer.print(", "); 479 printAnnotationsInline(tpe); 480 writer.print(tpe.toString()); 481 first = false; 482 } 483 484 writer.print(">"); 485 if (pad) 486 writer.print(" "); 487 } 488 } 489 490 private void printAnnotationsInline(Element e) { 491 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 492 for(AnnotationMirror annotationMirror : annots) { 493 writer.print(annotationMirror); 494 writer.print(" "); 495 } 496 } 497 498 private void printAnnotations(Element e) { 499 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 500 for(AnnotationMirror annotationMirror : annots) { 501 indent(); 502 writer.println(annotationMirror); 503 } 504 } 505 506 // TODO: Refactor 507 private void printParameters(ExecutableElement e) { 508 List<? extends VariableElement> parameters = e.getParameters(); 509 int size = parameters.size(); 510 511 switch (size) { 512 case 0: 513 break; 514 515 case 1: 516 for(VariableElement parameter: parameters) { 517 printModifiers(parameter); 518 519 if (e.isVarArgs() ) { 520 TypeMirror tm = parameter.asType(); 521 if (tm.getKind() != TypeKind.ARRAY) 522 throw new AssertionError("Var-args parameter is not an array type: " + tm); 523 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 524 writer.print("..."); 525 } else 526 writer.print(parameter.asType()); 527 writer.print(" " + parameter.getSimpleName()); 528 } 529 break; 530 531 default: 532 { 533 int i = 1; 534 for(VariableElement parameter: parameters) { 535 if (i == 2) 536 indentation++; 537 538 if (i > 1) 539 indent(); 540 541 printModifiers(parameter); 542 543 if (i == size && e.isVarArgs() ) { 544 TypeMirror tm = parameter.asType(); 545 if (tm.getKind() != TypeKind.ARRAY) 546 throw new AssertionError("Var-args parameter is not an array type: " + tm); 547 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 548 549 writer.print("..."); 550 } else 551 writer.print(parameter.asType()); 552 writer.print(" " + parameter.getSimpleName()); 553 554 if (i < size) 555 writer.println(","); 556 557 i++; 558 } 559 560 if (parameters.size() >= 2) 561 indentation--; 562 } 563 break; 564 } 565 } 566 567 private void printInterfaces(TypeElement e) { 568 ElementKind kind = e.getKind(); 569 570 if(kind != ANNOTATION_TYPE) { 571 List<? extends TypeMirror> interfaces = e.getInterfaces(); 572 if (interfaces.size() > 0) { 573 writer.print((kind.isClass() ? " implements" : " extends")); 574 575 boolean first = true; 576 for(TypeMirror interf: interfaces) { 577 if (!first) 578 writer.print(","); 579 writer.print(" "); 580 writer.print(interf.toString()); 581 first = false; 582 } 583 } 584 } 585 } 586 587 private void printThrows(ExecutableElement e) { 588 List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); 589 final int size = thrownTypes.size(); 590 if (size != 0) { 591 writer.print(" throws"); 592 593 int i = 1; 594 for(TypeMirror thrownType: thrownTypes) { 595 if (i == 1) 596 writer.print(" "); 597 598 if (i == 2) 599 indentation++; 600 601 if (i >= 2) 602 indent(); 603 604 writer.print(thrownType); 605 606 if (i != size) 607 writer.println(", "); 608 609 i++; 610 } 611 612 if (size >= 2) 613 indentation--; 614 } 615 } 616 617 private static final String [] spaces = { 618 "", 619 " ", 620 " ", 621 " ", 622 " ", 623 " ", 624 " ", 625 " ", 626 " ", 627 " ", 628 " " 629 }; 630 631 private void indent() { 632 int indentation = this.indentation; 633 if (indentation < 0) 634 return; 635 final int maxIndex = spaces.length - 1; 636 637 while (indentation > maxIndex) { 638 writer.print(spaces[maxIndex]); 639 indentation -= maxIndex; 640 } 641 writer.print(spaces[indentation]); 642 } 643 644 } 645} 646