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