duke@1: /* ohair@554: * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.processing; duke@1: duke@1: import javax.annotation.processing.*; duke@1: import javax.lang.model.*; duke@1: import javax.lang.model.element.*; duke@1: import static javax.lang.model.element.ElementKind.*; duke@1: import static javax.lang.model.element.NestingKind.*; duke@1: import javax.lang.model.type.*; duke@1: import javax.lang.model.util.*; duke@1: duke@1: import java.io.PrintWriter; duke@1: import java.io.Writer; duke@1: import java.util.*; duke@1: duke@1: /** duke@1: * A processor which prints out elements. Used to implement the duke@1: * -Xprint option; the included visitor class is used to implement duke@1: * Elements.printElements. duke@1: * jjg@581: *

This is NOT part of any supported API. duke@1: * If you write code that depends on this, you do so at your own risk. duke@1: * This code and its internal interfaces are subject to change or duke@1: * deletion without notice. duke@1: */ duke@1: @SupportedAnnotationTypes("*") darcy@381: // TODO: Change to version 7 based visitors when available darcy@381: @SupportedSourceVersion(SourceVersion.RELEASE_7) duke@1: public class PrintingProcessor extends AbstractProcessor { duke@1: PrintWriter writer; duke@1: duke@1: public PrintingProcessor() { duke@1: super(); duke@1: writer = new PrintWriter(System.out); duke@1: } duke@1: duke@1: public void setWriter(Writer w) { duke@1: writer = new PrintWriter(w); duke@1: } duke@1: duke@1: @Override duke@1: public boolean process(Set tes, duke@1: RoundEnvironment renv) { duke@1: duke@1: for(Element element : renv.getRootElements()) { duke@1: print(element); duke@1: } duke@1: duke@1: // Just print the elements, nothing more to do. duke@1: return true; duke@1: } duke@1: duke@1: void print(Element element) { duke@1: new PrintingElementVisitor(writer, processingEnv.getElementUtils()). duke@1: visit(element).flush(); duke@1: } duke@1: duke@1: /** duke@1: * Used for the -Xprint option and called by Elements.printElements duke@1: */ duke@1: public static class PrintingElementVisitor darcy@575: extends SimpleElementVisitor7 { duke@1: int indentation; // Indentation level; duke@1: final PrintWriter writer; duke@1: final Elements elementUtils; duke@1: duke@1: public PrintingElementVisitor(Writer w, Elements elementUtils) { duke@1: super(); duke@1: this.writer = new PrintWriter(w); duke@1: this.elementUtils = elementUtils; duke@1: indentation = 0; duke@1: } duke@1: duke@1: @Override duke@1: protected PrintingElementVisitor defaultAction(Element e, Boolean newLine) { duke@1: if (newLine != null && newLine) duke@1: writer.println(); duke@1: printDocComment(e); duke@1: printModifiers(e); duke@1: return this; duke@1: } duke@1: duke@1: @Override duke@1: public PrintingElementVisitor visitExecutable(ExecutableElement e, Boolean p) { duke@1: ElementKind kind = e.getKind(); duke@1: duke@1: if (kind != STATIC_INIT && duke@1: kind != INSTANCE_INIT) { duke@1: Element enclosing = e.getEnclosingElement(); duke@1: duke@1: // Don't print out the constructor of an anonymous class duke@1: if (kind == CONSTRUCTOR && duke@1: enclosing != null && duke@1: NestingKind.ANONYMOUS == duke@1: // Use an anonymous class to determine anonymity! darcy@575: (new SimpleElementVisitor7() { duke@1: @Override duke@1: public NestingKind visitType(TypeElement e, Void p) { duke@1: return e.getNestingKind(); duke@1: } duke@1: }).visit(enclosing)) duke@1: return this; duke@1: duke@1: defaultAction(e, true); darcy@224: printFormalTypeParameters(e, true); duke@1: duke@1: switch(kind) { duke@1: case CONSTRUCTOR: duke@1: // Print out simple name of the class duke@1: writer.print(e.getEnclosingElement().getSimpleName()); duke@1: break; duke@1: duke@1: case METHOD: duke@1: writer.print(e.getReturnType().toString()); duke@1: writer.print(" "); duke@1: writer.print(e.getSimpleName().toString()); duke@1: break; duke@1: } duke@1: duke@1: writer.print("("); duke@1: printParameters(e); duke@1: writer.print(")"); duke@1: AnnotationValue defaultValue = e.getDefaultValue(); duke@1: if (defaultValue != null) duke@1: writer.print(" default " + defaultValue); duke@1: duke@1: printThrows(e); duke@1: writer.println(";"); duke@1: } duke@1: return this; duke@1: } duke@1: duke@1: duke@1: @Override duke@1: public PrintingElementVisitor visitType(TypeElement e, Boolean p) { duke@1: ElementKind kind = e.getKind(); duke@1: NestingKind nestingKind = e.getNestingKind(); duke@1: duke@1: if (NestingKind.ANONYMOUS == nestingKind) { duke@1: // Print out an anonymous class in the style of a duke@1: // class instance creation expression rather than a duke@1: // class declaration. duke@1: writer.print("new "); duke@1: duke@1: // If the anonymous class implements an interface duke@1: // print that name, otherwise print the superclass. duke@1: List interfaces = e.getInterfaces(); duke@1: if (!interfaces.isEmpty()) duke@1: writer.print(interfaces.get(0)); duke@1: else duke@1: writer.print(e.getSuperclass()); duke@1: duke@1: writer.print("("); duke@1: // Anonymous classes that implement an interface can't duke@1: // have any constructor arguments. duke@1: if (interfaces.isEmpty()) { duke@1: // Print out the parameter list from the sole duke@1: // constructor. For now, don't try to elide any duke@1: // synthetic parameters by determining if the duke@1: // anonymous class is in a static context, etc. duke@1: List constructors = duke@1: ElementFilter.constructorsIn(e.getEnclosedElements()); duke@1: duke@1: if (!constructors.isEmpty()) duke@1: printParameters(constructors.get(0)); duke@1: } duke@1: writer.print(")"); duke@1: } else { duke@1: if (nestingKind == TOP_LEVEL) { duke@1: PackageElement pkg = elementUtils.getPackageOf(e); duke@1: if (!pkg.isUnnamed()) duke@1: writer.print("package " + pkg.getQualifiedName() + ";\n"); duke@1: } duke@1: duke@1: defaultAction(e, true); duke@1: duke@1: switch(kind) { duke@1: case ANNOTATION_TYPE: duke@1: writer.print("@interface"); duke@1: break; duke@1: default: duke@1: writer.print(kind.toString().toLowerCase()); duke@1: } duke@1: writer.print(" "); duke@1: writer.print(e.getSimpleName()); duke@1: darcy@224: printFormalTypeParameters(e, false); duke@1: duke@1: // Print superclass information if informative duke@1: if (kind == CLASS) { duke@1: TypeMirror supertype = e.getSuperclass(); duke@1: if (supertype.getKind() != TypeKind.NONE) { duke@1: TypeElement e2 = (TypeElement) duke@1: ((DeclaredType) supertype).asElement(); duke@1: if (e2.getSuperclass().getKind() != TypeKind.NONE) duke@1: writer.print(" extends " + supertype); duke@1: } duke@1: } duke@1: duke@1: printInterfaces(e); duke@1: } duke@1: writer.println(" {"); duke@1: indentation++; duke@1: duke@1: if (kind == ENUM) { duke@1: List enclosedElements = duke@1: new ArrayList(e.getEnclosedElements()); darcy@530: // Handle any enum constants specially before other entities. duke@1: List enumConstants = new ArrayList(); duke@1: for(Element element : enclosedElements) { duke@1: if (element.getKind() == ENUM_CONSTANT) duke@1: enumConstants.add(element); duke@1: } darcy@530: if (!enumConstants.isEmpty()) { darcy@530: int i; darcy@530: for(i = 0; i < enumConstants.size()-1; i++) { darcy@530: this.visit(enumConstants.get(i), true); darcy@530: writer.print(","); darcy@530: } darcy@530: this.visit(enumConstants.get(i), true); darcy@530: writer.println(";\n"); duke@1: darcy@530: enclosedElements.removeAll(enumConstants); duke@1: } duke@1: duke@1: for(Element element : enclosedElements) duke@1: this.visit(element); duke@1: } else { duke@1: for(Element element : e.getEnclosedElements()) duke@1: this.visit(element); duke@1: } duke@1: duke@1: indentation--; duke@1: indent(); duke@1: writer.println("}"); duke@1: return this; duke@1: } duke@1: duke@1: @Override duke@1: public PrintingElementVisitor visitVariable(VariableElement e, Boolean newLine) { duke@1: ElementKind kind = e.getKind(); duke@1: defaultAction(e, newLine); duke@1: duke@1: if (kind == ENUM_CONSTANT) duke@1: writer.print(e.getSimpleName()); duke@1: else { duke@1: writer.print(e.asType().toString() + " " + e.getSimpleName() ); duke@1: Object constantValue = e.getConstantValue(); duke@1: if (constantValue != null) { duke@1: writer.print(" = "); duke@1: writer.print(elementUtils.getConstantExpression(constantValue)); duke@1: } duke@1: writer.println(";"); duke@1: } duke@1: return this; duke@1: } duke@1: duke@1: @Override duke@1: public PrintingElementVisitor visitTypeParameter(TypeParameterElement e, Boolean p) { duke@1: writer.print(e.getSimpleName()); duke@1: return this; duke@1: } duke@1: duke@1: // Should we do more here? duke@1: @Override duke@1: public PrintingElementVisitor visitPackage(PackageElement e, Boolean p) { duke@1: defaultAction(e, false); duke@1: if (!e.isUnnamed()) duke@1: writer.println("package " + e.getQualifiedName() + ";"); duke@1: else duke@1: writer.println("// Unnamed package"); duke@1: return this; duke@1: } duke@1: duke@1: public void flush() { duke@1: writer.flush(); duke@1: } duke@1: duke@1: private void printDocComment(Element e) { duke@1: String docComment = elementUtils.getDocComment(e); duke@1: duke@1: if (docComment != null) { duke@1: // Break comment into lines duke@1: java.util.StringTokenizer st = new StringTokenizer(docComment, duke@1: "\n\r"); duke@1: indent(); duke@1: writer.println("/**"); duke@1: duke@1: while(st.hasMoreTokens()) { duke@1: indent(); duke@1: writer.print(" *"); duke@1: writer.println(st.nextToken()); duke@1: } duke@1: duke@1: indent(); duke@1: writer.println(" */"); duke@1: } duke@1: } duke@1: duke@1: private void printModifiers(Element e) { duke@1: ElementKind kind = e.getKind(); duke@1: if (kind == PARAMETER) { duke@1: printAnnotationsInline(e); duke@1: } else { duke@1: printAnnotations(e); duke@1: indent(); duke@1: } duke@1: duke@1: if (kind == ENUM_CONSTANT) duke@1: return; duke@1: duke@1: Set modifiers = new LinkedHashSet(); duke@1: modifiers.addAll(e.getModifiers()); duke@1: duke@1: switch (kind) { duke@1: case ANNOTATION_TYPE: duke@1: case INTERFACE: duke@1: modifiers.remove(Modifier.ABSTRACT); duke@1: break; duke@1: duke@1: case ENUM: duke@1: modifiers.remove(Modifier.FINAL); duke@1: modifiers.remove(Modifier.ABSTRACT); duke@1: break; duke@1: duke@1: case METHOD: duke@1: case FIELD: duke@1: Element enclosingElement = e.getEnclosingElement(); duke@1: if (enclosingElement != null && duke@1: enclosingElement.getKind().isInterface()) { duke@1: modifiers.remove(Modifier.PUBLIC); duke@1: modifiers.remove(Modifier.ABSTRACT); // only for methods duke@1: modifiers.remove(Modifier.STATIC); // only for fields duke@1: modifiers.remove(Modifier.FINAL); // only for fields duke@1: } duke@1: break; duke@1: duke@1: } duke@1: duke@1: for(Modifier m: modifiers) { duke@1: writer.print(m.toString() + " "); duke@1: } duke@1: } duke@1: darcy@224: private void printFormalTypeParameters(Parameterizable e, duke@1: boolean pad) { darcy@224: List typeParams = e.getTypeParameters(); duke@1: if (typeParams.size() > 0) { duke@1: writer.print("<"); duke@1: duke@1: boolean first = true; duke@1: for(TypeParameterElement tpe: typeParams) { duke@1: if (!first) duke@1: writer.print(", "); darcy@381: printAnnotationsInline(tpe); duke@1: writer.print(tpe.toString()); duke@1: first = false; duke@1: } duke@1: duke@1: writer.print(">"); duke@1: if (pad) duke@1: writer.print(" "); duke@1: } duke@1: } duke@1: duke@1: private void printAnnotationsInline(Element e) { duke@1: List annots = e.getAnnotationMirrors(); duke@1: for(AnnotationMirror annotationMirror : annots) { duke@1: writer.print(annotationMirror); duke@1: writer.print(" "); duke@1: } duke@1: } duke@1: duke@1: private void printAnnotations(Element e) { duke@1: List annots = e.getAnnotationMirrors(); duke@1: for(AnnotationMirror annotationMirror : annots) { duke@1: indent(); duke@1: writer.println(annotationMirror); duke@1: } duke@1: } duke@1: duke@1: // TODO: Refactor duke@1: private void printParameters(ExecutableElement e) { duke@1: List parameters = e.getParameters(); duke@1: int size = parameters.size(); duke@1: duke@1: switch (size) { duke@1: case 0: duke@1: break; duke@1: duke@1: case 1: duke@1: for(VariableElement parameter: parameters) { duke@1: printModifiers(parameter); duke@1: duke@1: if (e.isVarArgs() ) { duke@1: TypeMirror tm = parameter.asType(); duke@1: if (tm.getKind() != TypeKind.ARRAY) duke@1: throw new AssertionError("Var-args parameter is not an array type: " + tm); duke@1: writer.print((ArrayType.class.cast(tm)).getComponentType() ); duke@1: writer.print("..."); duke@1: } else duke@1: writer.print(parameter.asType()); duke@1: writer.print(" " + parameter.getSimpleName()); duke@1: } duke@1: break; duke@1: duke@1: default: duke@1: { duke@1: int i = 1; duke@1: for(VariableElement parameter: parameters) { duke@1: if (i == 2) duke@1: indentation++; duke@1: duke@1: if (i > 1) duke@1: indent(); duke@1: duke@1: printModifiers(parameter); duke@1: duke@1: if (i == size && e.isVarArgs() ) { duke@1: TypeMirror tm = parameter.asType(); duke@1: if (tm.getKind() != TypeKind.ARRAY) duke@1: throw new AssertionError("Var-args parameter is not an array type: " + tm); duke@1: writer.print((ArrayType.class.cast(tm)).getComponentType() ); duke@1: duke@1: writer.print("..."); duke@1: } else duke@1: writer.print(parameter.asType()); duke@1: writer.print(" " + parameter.getSimpleName()); duke@1: duke@1: if (i < size) duke@1: writer.println(","); duke@1: duke@1: i++; duke@1: } duke@1: duke@1: if (parameters.size() >= 2) duke@1: indentation--; duke@1: } duke@1: break; duke@1: } duke@1: } duke@1: duke@1: private void printInterfaces(TypeElement e) { duke@1: ElementKind kind = e.getKind(); duke@1: duke@1: if(kind != ANNOTATION_TYPE) { duke@1: List interfaces = e.getInterfaces(); duke@1: if (interfaces.size() > 0) { duke@1: writer.print((kind.isClass() ? " implements" : " extends")); duke@1: duke@1: boolean first = true; duke@1: for(TypeMirror interf: interfaces) { duke@1: if (!first) duke@1: writer.print(","); duke@1: writer.print(" "); duke@1: writer.print(interf.toString()); duke@1: first = false; duke@1: } duke@1: } duke@1: } duke@1: } duke@1: duke@1: private void printThrows(ExecutableElement e) { duke@1: List thrownTypes = e.getThrownTypes(); duke@1: final int size = thrownTypes.size(); duke@1: if (size != 0) { duke@1: writer.print(" throws"); duke@1: duke@1: int i = 1; duke@1: for(TypeMirror thrownType: thrownTypes) { duke@1: if (i == 1) duke@1: writer.print(" "); duke@1: duke@1: if (i == 2) duke@1: indentation++; duke@1: duke@1: if (i >= 2) duke@1: indent(); duke@1: duke@1: writer.print(thrownType); duke@1: duke@1: if (i != size) duke@1: writer.println(", "); duke@1: duke@1: i++; duke@1: } duke@1: duke@1: if (size >= 2) duke@1: indentation--; duke@1: } duke@1: } duke@1: duke@1: private static final String [] spaces = { duke@1: "", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " ", duke@1: " " duke@1: }; duke@1: duke@1: private void indent() { duke@1: int indentation = this.indentation; duke@1: if (indentation < 0) duke@1: return; duke@1: final int maxIndex = spaces.length - 1; duke@1: duke@1: while (indentation > maxIndex) { duke@1: writer.print(spaces[maxIndex]); duke@1: indentation -= maxIndex; duke@1: } duke@1: writer.print(spaces[indentation]); duke@1: } duke@1: duke@1: } duke@1: }