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

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