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