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 43 import com.sun.tools.javac.util.DefinedBy; 44 import com.sun.tools.javac.util.DefinedBy.Api; 45 import 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_14) 59 public 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 SimpleElementVisitor9<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 // Print annotation inline 428 writer.print(annotationsToString(e)); 429 } else { 430 printAnnotations(e); 431 indent(); 432 } 433 434 if (kind == ENUM_CONSTANT) 435 return; 436 437 Set<Modifier> modifiers = new LinkedHashSet<>(); 438 modifiers.addAll(e.getModifiers()); 439 440 switch (kind) { 441 case ANNOTATION_TYPE: 442 case INTERFACE: 443 modifiers.remove(Modifier.ABSTRACT); 444 break; 445 446 case ENUM: 447 modifiers.remove(Modifier.FINAL); 448 modifiers.remove(Modifier.ABSTRACT); 449 break; 450 451 case METHOD: 452 case FIELD: 453 Element enclosingElement = e.getEnclosingElement(); 454 if (enclosingElement != null && 455 enclosingElement.getKind().isInterface()) { 456 modifiers.remove(Modifier.PUBLIC); 457 modifiers.remove(Modifier.ABSTRACT); // only for methods 458 modifiers.remove(Modifier.STATIC); // only for fields 459 modifiers.remove(Modifier.FINAL); // only for fields 460 } 461 break; 462 463 } 464 if (!modifiers.isEmpty()) { 465 writer.print(modifiers.stream() 466 .map(Modifier::toString) 467 .collect(Collectors.joining(" ", "", " "))); 468 } 469 } 470 471 private void printFormalTypeParameters(Parameterizable e, 472 boolean pad) { 473 List<? extends TypeParameterElement> typeParams = e.getTypeParameters(); 474 if (!typeParams.isEmpty()) { 475 writer.print(typeParams.stream() 476 .map(tpe -> annotationsToString(tpe) + tpe.toString()) 477 .collect(Collectors.joining(", ", "<", ">"))); 478 if (pad) 479 writer.print(" "); 480 } 481 } 482 483 private String annotationsToString(Element e) { 484 List<? extends AnnotationMirror> annotations = e.getAnnotationMirrors(); 485 return annotations.isEmpty() ? 486 "" : 487 annotations.stream() 488 .map(AnnotationMirror::toString) 489 .collect(Collectors.joining(" ", "", " ")); 490 } 491 492 private void printAnnotations(Element e) { 493 List<? extends AnnotationMirror> annots = e.getAnnotationMirrors(); 494 for(AnnotationMirror annotationMirror : annots) { 495 indent(); 496 writer.println(annotationMirror); 497 } 498 } 499 500 // TODO: Refactor 501 private void printParameters(ExecutableElement e) { 502 List<? extends VariableElement> parameters = e.getParameters(); 503 int size = parameters.size(); 504 505 switch (size) { 506 case 0: 507 break; 508 509 case 1: 510 for(VariableElement parameter: parameters) { 511 printModifiers(parameter); 512 513 if (e.isVarArgs() ) { 514 TypeMirror tm = parameter.asType(); 515 if (tm.getKind() != TypeKind.ARRAY) 516 throw new AssertionError("Var-args parameter is not an array type: " + tm); 517 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 518 writer.print("..."); 519 } else 520 writer.print(parameter.asType()); 521 writer.print(" " + parameter.getSimpleName()); 522 } 523 break; 524 525 default: 526 { 527 int i = 1; 528 for(VariableElement parameter: parameters) { 529 if (i == 2) 530 indentation++; 531 532 if (i > 1) 533 indent(); 534 535 printModifiers(parameter); 536 537 if (i == size && e.isVarArgs() ) { 538 TypeMirror tm = parameter.asType(); 539 if (tm.getKind() != TypeKind.ARRAY) 540 throw new AssertionError("Var-args parameter is not an array type: " + tm); 541 writer.print((ArrayType.class.cast(tm)).getComponentType() ); 542 543 writer.print("..."); 544 } else 545 writer.print(parameter.asType()); 546 writer.print(" " + parameter.getSimpleName()); 547 548 if (i < size) 549 writer.println(","); 550 551 i++; 552 } 553 554 if (parameters.size() >= 2) 555 indentation--; 556 } 557 break; 558 } 559 } 560 561 private void printInterfaces(TypeElement e) { 562 ElementKind kind = e.getKind(); 563 564 if(kind != ANNOTATION_TYPE) { 565 List<? extends TypeMirror> interfaces = e.getInterfaces(); 566 if (!interfaces.isEmpty()) { 567 writer.print((kind.isClass() ? " implements " : " extends ")); 568 writer.print(interfaces.stream() 569 .map(TypeMirror::toString) 570 .collect(Collectors.joining(", "))); 571 } 572 } 573 } 574 575 private void printThrows(ExecutableElement e) { 576 List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); 577 final int size = thrownTypes.size(); 578 if (size != 0) { 579 writer.print(" throws"); 580 581 int i = 1; 582 for(TypeMirror thrownType: thrownTypes) { 583 if (i == 1) 584 writer.print(" "); 585 586 if (i == 2) 587 indentation++; 588 589 if (i >= 2) 590 indent(); 591 592 writer.print(thrownType); 593 594 if (i != size) 595 writer.println(", "); 596 597 i++; 598 } 599 600 if (size >= 2) 601 indentation--; 602 } 603 } 604 605 private static final String [] spaces = { 606 "", 607 " ", 608 " ", 609 " ", 610 " ", 611 " ", 612 " ", 613 " ", 614 " ", 615 " ", 616 " " 617 }; 618 619 private void indent() { 620 int indentation = this.indentation; 621 if (indentation < 0) 622 return; 623 final int maxIndex = spaces.length - 1; 624 625 while (indentation > maxIndex) { 626 writer.print(spaces[maxIndex]); 627 indentation -= maxIndex; 628 } 629 writer.print(spaces[indentation]); 630 } 631 632 } 633 }