duke@1: /*
ohair@798: * Copyright (c) 2005, 2010, 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 extends TypeElement> 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 extends TypeMirror> 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 extends ExecutableElement> 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 extends TypeParameterElement> 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 extends AnnotationMirror> 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 extends AnnotationMirror> 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 extends VariableElement> 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 extends TypeMirror> 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 extends TypeMirror> 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: }