All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lombok.javac.handlers.ast.JavacASTMaker Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2011-2012 Philipp Eichhorn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package lombok.javac.handlers.ast;

import static lombok.ast.AST.*;
import static lombok.javac.handlers.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.setGeneratedBy;
import static com.sun.tools.javac.code.Flags.*;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCCase;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCIf;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCSwitch;
import com.sun.tools.javac.tree.JCTree.JCSynchronized;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.JCTree.JCTry;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;

import lombok.RequiredArgsConstructor;
import lombok.core.util.As;
import lombok.core.util.Cast;
import lombok.javac.Javac;
import lombok.javac.JavacNode;

@RequiredArgsConstructor
public final class JavacASTMaker implements lombok.ast.ASTVisitor {
	private static final Map UNARY_OPERATORS = new HashMap();
	static {
		UNARY_OPERATORS.put("+", Javac.getCtcInt(JCTree.class, "POS"));
		UNARY_OPERATORS.put("-", Javac.getCtcInt(JCTree.class, "NEG"));
		UNARY_OPERATORS.put("!", Javac.getCtcInt(JCTree.class, "NOT"));
		UNARY_OPERATORS.put("~", Javac.getCtcInt(JCTree.class, "COMPL"));
		UNARY_OPERATORS.put("++X", Javac.getCtcInt(JCTree.class, "PREINC"));
		UNARY_OPERATORS.put("--X", Javac.getCtcInt(JCTree.class, "PREDEC"));
		UNARY_OPERATORS.put("X++", Javac.getCtcInt(JCTree.class, "POSTINC"));
		UNARY_OPERATORS.put("X--", Javac.getCtcInt(JCTree.class, "POSTDEC"));
	}
	private static final Map BINARY_OPERATORS = new HashMap();
	static {
		BINARY_OPERATORS.put("||", Javac.getCtcInt(JCTree.class, "OR"));
		BINARY_OPERATORS.put("&&", Javac.getCtcInt(JCTree.class, "AND"));
		BINARY_OPERATORS.put("==", Javac.getCtcInt(JCTree.class, "EQ"));
		BINARY_OPERATORS.put("!=", Javac.getCtcInt(JCTree.class, "NE"));
		BINARY_OPERATORS.put("<", Javac.getCtcInt(JCTree.class, "LT"));
		BINARY_OPERATORS.put(">", Javac.getCtcInt(JCTree.class, "GT"));
		BINARY_OPERATORS.put("<=", Javac.getCtcInt(JCTree.class, "LE"));
		BINARY_OPERATORS.put(">=", Javac.getCtcInt(JCTree.class, "GE"));
		BINARY_OPERATORS.put("|", Javac.getCtcInt(JCTree.class, "BITOR"));
		BINARY_OPERATORS.put("^", Javac.getCtcInt(JCTree.class, "BITXOR"));
		BINARY_OPERATORS.put("&", Javac.getCtcInt(JCTree.class, "BITAND"));
		BINARY_OPERATORS.put("<<", Javac.getCtcInt(JCTree.class, "SL"));
		BINARY_OPERATORS.put(">>", Javac.getCtcInt(JCTree.class, "SR"));
		BINARY_OPERATORS.put(">>>", Javac.getCtcInt(JCTree.class, "USR"));
		BINARY_OPERATORS.put("+", Javac.getCtcInt(JCTree.class, "PLUS"));
		BINARY_OPERATORS.put("-", Javac.getCtcInt(JCTree.class, "MINUS"));
		BINARY_OPERATORS.put("*", Javac.getCtcInt(JCTree.class, "MUL"));
		BINARY_OPERATORS.put("/", Javac.getCtcInt(JCTree.class, "DIV"));
		BINARY_OPERATORS.put("%", Javac.getCtcInt(JCTree.class, "MOD"));
	}
	private static final Map TYPES = new HashMap();
	static {
		TYPES.put("none", Javac.getCtcInt(TypeTags.class, "NONE"));
		TYPES.put("null", Javac.getCtcInt(TypeTags.class, "BOT"));
		TYPES.put("void", Javac.getCtcInt(TypeTags.class, "VOID"));
		TYPES.put("int", Javac.getCtcInt(TypeTags.class, "INT"));
		TYPES.put("long", Javac.getCtcInt(TypeTags.class, "LONG"));
		TYPES.put("short", Javac.getCtcInt(TypeTags.class, "SHORT"));
		TYPES.put("boolean", Javac.getCtcInt(TypeTags.class, "BOOLEAN"));
		TYPES.put("byte", Javac.getCtcInt(TypeTags.class, "BYTE"));
		TYPES.put("char", Javac.getCtcInt(TypeTags.class, "CHAR"));
		TYPES.put("float", Javac.getCtcInt(TypeTags.class, "FLOAT"));
		TYPES.put("double", Javac.getCtcInt(TypeTags.class, "DOUBLE"));
	}

	private final JavacNode sourceNode;
	private final JCTree source;

	public  T build(final lombok.ast.Node node) {
		return this. build(node, null);
	}

	public  T build(final lombok.ast.Node node, final Class extectedType) {
		if (node == null) return null;
		JCTree tree = node.accept(this, null);
		if ((JCStatement.class == extectedType) && (tree instanceof JCExpression)) {
			tree = M(node).Exec((JCExpression) tree);
		}
		return Cast. uncheckedCast(tree);
	}

	public  List build(final java.util.List> nodes) {
		return this. build(nodes, null);
	}

	public  List build(final java.util.List> nodes, final Class extectedType) {
		if (nodes == null) return null;
		ListBuffer list = ListBuffer.lb();
		for (lombok.ast.Node node : nodes) {
			list.append(build(node, extectedType));
		}
		return list.toList();
	}

	private TreeMaker M(final lombok.ast.Node node) {
		final int pos;
		if ((node.upTo(lombok.ast.EnumConstant.class) != null) || (node.upTo(lombok.ast.FieldDecl.class) != null)) {
			pos = -1;
		} else {
			final JCTree posHint = node.posHint();
			pos = posHint == null ? source.pos : posHint.pos;
		}
		return sourceNode.getTreeMaker().at(pos);
	}

	private Name name(final String name) {
		return sourceNode.toName(name);
	}

	private JCExpression chainDots(final lombok.ast.Node node, final String name) {
		String[] elements = name.split("\\.");
		JCExpression e = M(node).Ident(name(elements[0]));
		for (int i = 1, iend = elements.length; i < iend; i++) {
			e = M(node).Select(e, name(elements[i]));
		}
		return e;
	}

	private JCExpression fixLeadingDot(final lombok.ast.Node node, final JCExpression expr) {
		if (expr instanceof JCFieldAccess) {
			JCFieldAccess fieldAccess = (JCFieldAccess) expr;
			JCExpression selExpr = fieldAccess.selected;
			if (selExpr instanceof JCIdent) {
				if ("".equals(selExpr.toString())) {
					return M(node).Ident(fieldAccess.name);
				}
			} else if (selExpr instanceof JCFieldAccess) {
				fieldAccess.selected = fixLeadingDot(node, selExpr);
			}
		}
		return expr;
	}

	private long flagsFor(final Set modifiers) {
		long flags = 0;
		flags |= modifiers.contains(lombok.ast.Modifier.FINAL) ? FINAL : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.PRIVATE) ? PRIVATE : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.PROTECTED) ? PROTECTED : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.PUBLIC) ? PUBLIC : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.STATIC) ? STATIC : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.TRANSIENT) ? TRANSIENT : 0;
		flags |= modifiers.contains(lombok.ast.Modifier.VOLATILE) ? VOLATILE : 0;
		return flags;
	}

	private JCTree withJavaDoc(final JCTree target, final lombok.ast.JavaDoc javaDoc) {
		final JCLiteral javadocExp = build(javaDoc, JCLiteral.class);
		if (javadocExp != null) {
			final JCCompilationUnit compilationUnit = (JCCompilationUnit) sourceNode.top().get();
			compilationUnit.docComments.put(target, As.string(javadocExp.getValue()));
		}
		return target;
	}

	@Override
	public JCTree visitAnnotation(final lombok.ast.Annotation node, final Void p) {
		final ListBuffer args = ListBuffer.lb();
		for (Entry> entry : node.getValues().entrySet()) {
			args.append(build(Assign(Name(entry.getKey()), entry.getValue()), JCExpression.class));
		}
		final JCAnnotation annotation = setGeneratedBy(M(node).Annotation(build(node.getType()), args.toList()), source);
		return annotation;
	}

	@Override
	public JCTree visitArgument(final lombok.ast.Argument node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		final JCVariableDecl argument = setGeneratedBy(M(node).VarDef(mods, name(node.getName()), build(node.getType(), JCExpression.class), null), source);
		return argument;
	}

	@Override
	public JCTree visitArrayRef(final lombok.ast.ArrayRef node, final Void p) {
		final JCArrayAccess arrayAccess = setGeneratedBy(M(node).Indexed(build(node.getIndexed(), JCExpression.class), build(node.getIndex(), JCExpression.class)), source);
		return arrayAccess;
	}

	@Override
	public JCTree visitAssignment(final lombok.ast.Assignment node, final Void p) {
		final JCAssign assignment = setGeneratedBy(M(node).Assign(build(node.getLeft(), JCExpression.class), build(node.getRight(), JCExpression.class)), source);
		return assignment;
	}

	@Override
	public JCTree visitBinary(final lombok.ast.Binary node, final Void p) {
		final String operator = node.getOperator();
		final int opCode;
		if (BINARY_OPERATORS.containsKey(operator)) {
			opCode = BINARY_OPERATORS.get(operator);
		} else {
			throw new IllegalStateException(String.format("Unknown binary operator '%s'", operator));
		}
		JCBinary binary = setGeneratedBy(M(node).Binary(opCode, build(node.getLeft(), JCExpression.class), build(node.getRight(), JCExpression.class)), source);
		return binary;
	}

	@Override
	public JCTree visitBlock(final lombok.ast.Block node, final Void p) {
		final JCBlock block = setGeneratedBy(M(node).Block(0, build(node.getStatements(), JCStatement.class)), source);
		return block;
	}

	@Override
	public JCTree visitBooleanLiteral(final lombok.ast.BooleanLiteral node, final Void p) {
		final JCLiteral literal = setGeneratedBy(M(node).Literal(TYPES.get("boolean"), node.isTrue() ? 1 : 0), source);
		return literal;
	}

	@Override
	public JCTree visitBreak(final lombok.ast.Break node, final Void p) {
		final JCBreak breakStatement = setGeneratedBy(M(node).Break(node.getLabel() == null ? null : name(node.getLabel())), source);
		return breakStatement;
	}

	@Override
	public JCTree visitCall(final lombok.ast.Call node, final Void p) {
		final JCExpression fn;
		if (node.getReceiver() == null) {
			fn = M(node).Ident(name(node.getName()));
		} else {
			fn = M(node).Select(build(node.getReceiver(), JCExpression.class), name(node.getName()));
		}
		final JCMethodInvocation methodInvocation = setGeneratedBy(M(node).Apply(build(node.getTypeArgs(), JCExpression.class), fn, build(node.getArgs(), JCExpression.class)),
				source);
		return methodInvocation;
	}

	@Override
	public JCTree visitCase(final lombok.ast.Case node, final Void p) {
		final JCCase caze = setGeneratedBy(M(node).Case(build(node.getPattern(), JCExpression.class), build(node.getStatements(), JCStatement.class)), source);
		return caze;
	}

	@Override
	public JCTree visitCast(final lombok.ast.Cast node, final Void p) {
		final JCTypeCast cast = setGeneratedBy(M(node).TypeCast(build(node.getType()), build(node.getExpression(), JCExpression.class)), source);
		return cast;
	}

	@Override
	public JCTree visitCharLiteral(final lombok.ast.CharLiteral node, final Void p) {
		final JCLiteral literal = setGeneratedBy(M(node).Literal(node.getCharacter().charAt(0)), source);
		return literal;
	}

	@Override
	public JCTree visitClassDecl(final lombok.ast.ClassDecl node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		if (node.isInterface()) mods.flags |= Flags.INTERFACE;
		final ListBuffer defs = ListBuffer.lb();
		defs.appendList(build(node.getFields()));
		defs.appendList(build(node.getMethods()));
		defs.appendList(build(node.getMemberTypes()));
		final List typarams = build(node.getTypeParameters());
		final JCExpression extending = build(node.getSuperclass());
		final List implementing = build(node.getSuperInterfaces());
		final JCClassDecl classDecl = setGeneratedBy(createClassDef(node, mods, name(node.getName()), typarams, extending, implementing, defs.toList()), source);
		return classDecl;
	}

	// to support both:
	// javac 1.6 - M(node).ClassDef(JCModifiers, Name, List, JCTree, List, List)
	// and javac 1.7 - M(node).ClassDef(JCModifiers, Name, List, JCExpression, List,
	// List)
	private JCClassDecl createClassDef(final lombok.ast.Node node, final JCModifiers mods, final Name name, final List typarams, final JCExpression extending,
			final List implementing, final List defs) {
		try {
			Method classDefMethod = null;
			for (Method method : TreeMaker.class.getMethods()) {
				if ("ClassDef".equals(method.getName())) {
					classDefMethod = method;
					break;
				}
			}
			if (classDefMethod == null) throw new IllegalStateException();
			return (JCClassDecl) classDefMethod.invoke(M(node), mods, name, typarams, extending, implementing, defs);
		} catch (final Exception e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public JCTree visitConstructorDecl(final lombok.ast.ConstructorDecl node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		List statements = build(node.getStatements(), JCStatement.class);
		if (node.implicitSuper()) {
			statements = statements.prepend(build(Call("super"), JCStatement.class));
		}
		final List typarams = build(node.getTypeParameters());
		final List params = build(node.getArguments());
		final List thrown = build(node.getThrownExceptions());
		final JCBlock body = setGeneratedBy(M(node).Block(0, statements), source);
		final JCMethodDecl constructor = setGeneratedBy(M(node).MethodDef(mods, name(""), null, typarams, params, thrown, body, null), source);
		return withJavaDoc(constructor, node.getJavaDoc());
	}

	@Override
	public JCTree visitContinue(final lombok.ast.Continue node, final Void p) {
		final JCContinue continueStatement = setGeneratedBy(M(node).Continue(node.getLabel() == null ? null : name(node.getLabel())), source);
		return continueStatement;
	}

	@Override
	public JCTree visitDefaultValue(final lombok.ast.DefaultValue node, final Void p) {
		lombok.ast.Expression defaultValue = Null();
		final JCExpression type = build(node.getType());
		if (type instanceof JCPrimitiveTypeTree) {
			JCPrimitiveTypeTree primitiveType = (JCPrimitiveTypeTree) type;
			if (primitiveType.typetag == TYPES.get("void")) {
				defaultValue = null;
			} else {
				defaultValue = Expr(M(node).Literal(primitiveType.typetag, 0));
			}
		}
		return build(defaultValue);
	}

	@Override
	public JCTree visitDoWhile(final lombok.ast.DoWhile node, final Void p) {
		final JCDoWhileLoop doStatement = setGeneratedBy(M(node).DoLoop(build(node.getAction(), JCStatement.class), build(node.getCondition(), JCExpression.class)), source);
		return doStatement;
	}

	@Override
	public JCTree visitEnumConstant(final lombok.ast.EnumConstant node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(ENUM | STATIC | FINAL | PUBLIC, build(node.getAnnotations(), JCAnnotation.class)), source);
		lombok.ast.ClassDecl enumClassDecl = node.upTo(lombok.ast.ClassDecl.class);
		final JCExpression varType;
		if (enumClassDecl == null) {
			varType = build(Type(typeNodeOf(sourceNode).getName()));
		} else {
			varType = chainDots(node, enumClassDecl.getName());
		}
		final List nilExp = List.nil();
		final List args = build(node.getArgs());
		final JCNewClass init = setGeneratedBy(M(node).NewClass(null, nilExp, varType, args, null), source);
		final JCVariableDecl enumContant = setGeneratedBy(M(node).VarDef(mods, name(node.getName()), varType, init), source);
		return withJavaDoc(enumContant, node.getJavaDoc());
	}

	@Override
	public JCTree visitFieldDecl(final lombok.ast.FieldDecl node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		final JCExpression vartype = build(node.getType());
		final JCExpression init = build(node.getInitialization());
		final JCVariableDecl field = setGeneratedBy(M(node).VarDef(mods, name(node.getName()), vartype, init), source);
		return withJavaDoc(field, node.getJavaDoc());
	}

	@Override
	public JCTree visitFieldRef(final lombok.ast.FieldRef node, final Void p) {
		final Name fieldName = name(node.getName());
		if (node.getReceiver() == null) {
			return setGeneratedBy(M(node).Ident(fieldName), source);
		} else {
			return setGeneratedBy(M(node).Select(build(node.getReceiver(), JCExpression.class), fieldName), source);
		}
	}

	@Override
	public JCTree visitForeach(final lombok.ast.Foreach node, final Void p) {
		final JCVariableDecl var = build(node.getElementVariable());
		final JCExpression expr = build(node.getCollection());
		final JCStatement body = build(node.getAction(), JCStatement.class);
		final JCEnhancedForLoop foreach = setGeneratedBy(M(node).ForeachLoop(var, expr, body), source);
		return foreach;
	}

	@Override
	public JCTree visitIf(final lombok.ast.If node, final Void p) {
		final JCExpression cond = build(node.getCondition());
		final JCStatement thenpart = build(node.getThenStatement(), JCStatement.class);
		final JCStatement elsepart = build(node.getElseStatement(), JCStatement.class);
		final JCIf ifStatement = setGeneratedBy(M(node).If(cond, thenpart, elsepart), source);
		return ifStatement;
	}

	@Override
	public JCTree visitInitializer(lombok.ast.Initializer node, Void p) {
		final JCBlock block = setGeneratedBy(M(node).Block(flagsFor(node.getModifiers()), build(node.getStatements(), JCStatement.class)), source);
		return block;
	}

	@Override
	public JCTree visitInstanceOf(final lombok.ast.InstanceOf node, final Void p) {
		final JCInstanceOf instanceOf = setGeneratedBy(M(node).TypeTest(build(node.getExpression(), JCExpression.class), build(node.getType())), source);
		return instanceOf;
	}

	@Override
	public JCTree visitJavaDoc(final lombok.ast.JavaDoc node, final Void p) {
		final StringBuilder javadoc = new StringBuilder();
		if (node.getMessage() != null) javadoc.append(node.getMessage()).append("\n");
		for (Map.Entry argumentReference : node.getArgumentReferences().entrySet()) {
			javadoc.append("@param ").append(argumentReference.getKey()).append(" ").append(argumentReference.getValue()).append("\n");
		}
		for (Map.Entry paramTypeReference : node.getParamTypeReferences().entrySet()) {
			javadoc.append("@param <").append(paramTypeReference.getKey()).append("> ").append(paramTypeReference.getValue()).append("\n");
		}
		for (Map.Entry exceptionReference : node.getExceptionReferences().entrySet()) {
			javadoc.append("@throws ").append(exceptionReference.getKey().getTypeName()).append(" ").append(exceptionReference.getValue()).append("\n");
		}
		if (node.getReturnMessage() != null) javadoc.append("@return ").append(node.getReturnMessage()).append("\n");
		return M(node).Literal(javadoc.toString());
	}

	@Override
	public JCTree visitLocalDecl(final lombok.ast.LocalDecl node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		final JCExpression vartype = build(node.getType());
		final JCExpression init = build(node.getInitialization());
		final JCVariableDecl local = setGeneratedBy(M(node).VarDef(mods, name(node.getName()), vartype, init), source);
		return local;
	}

	@Override
	public JCTree visitMethodDecl(final lombok.ast.MethodDecl node, final Void p) {
		final JCModifiers mods = setGeneratedBy(M(node).Modifiers(flagsFor(node.getModifiers()), build(node.getAnnotations(), JCAnnotation.class)), source);
		final JCExpression restype = build(node.getReturnType());
		final List typarams = build(node.getTypeParameters());
		final List params = build(node.getArguments());
		final List thrown = build(node.getThrownExceptions());
		JCBlock body = null;
		if (!node.noBody() && ((mods.flags & Flags.ABSTRACT) == 0)) {
			body = setGeneratedBy(M(node).Block(0, build(node.getStatements(), JCStatement.class)), source);
		}
		final JCMethodDecl method = setGeneratedBy(M(node).MethodDef(mods, name(node.getName()), restype, typarams, params, thrown, body, null), source);
		return withJavaDoc(method, node.getJavaDoc());
	}

	@Override
	public JCTree visitNameRef(final lombok.ast.NameRef node, final Void p) {
		return setGeneratedBy(chainDots(node, node.getName()), source);
	}

	@Override
	public JCTree visitNew(final lombok.ast.New node, final Void p) {
		final List typeargs = build(node.getTypeArgs());
		final JCExpression clazz = build(node.getType());
		final List args = build(node.getArgs());
		final JCClassDecl def = build(node.getAnonymousType());
		final JCNewClass newClass = setGeneratedBy(M(node).NewClass(null, typeargs, clazz, args, def), source);
		return newClass;
	}

	@Override
	public JCTree visitNewArray(final lombok.ast.NewArray node, final Void p) {
		final ListBuffer dims = ListBuffer.lb();
		dims.appendList(build(node.getDimensionExpressions(), JCExpression.class));
		final JCExpression elemtype = build(node.getType());
		final List initializerExpressions = build(node.getInitializerExpressions(), JCExpression.class);
		JCNewArray newClass = setGeneratedBy(M(node).NewArray(elemtype, dims.toList(), initializerExpressions.isEmpty() ? null : initializerExpressions), source);
		return newClass;
	}

	@Override
	public JCTree visitNullLiteral(final lombok.ast.NullLiteral node, final Void p) {
		final JCLiteral literal = setGeneratedBy(M(node).Literal(TYPES.get("null"), null), source);
		return literal;
	}

	@Override
	public JCTree visitNumberLiteral(final lombok.ast.NumberLiteral node, final Void p) {
		final JCLiteral literal = setGeneratedBy(M(node).Literal(node.getNumber()), source);
		return literal;
	}

	@Override
	public JCTree visitReturn(final lombok.ast.Return node, final Void p) {
		final JCReturn returnStatement = setGeneratedBy(M(node).Return(build(node.getExpression(), JCExpression.class)), source);
		return returnStatement;
	}

	@Override
	public JCTree visitReturnDefault(final lombok.ast.ReturnDefault node, final Void p) {
		lombok.ast.TypeRef returnType = node.upTo(lombok.ast.MethodDecl.class).getReturnType();
		if (returnType == null) {
			returnType = Type(methodNodeOf(sourceNode).getName());
		}
		return build(Return(DefaultValue(returnType)));
	}

	@Override
	public JCTree visitStringLiteral(final lombok.ast.StringLiteral node, final Void p) {
		final JCLiteral literal = setGeneratedBy(M(node).Literal(node.getString()), source);
		return literal;
	}

	@Override
	public JCTree visitSwitch(final lombok.ast.Switch node, final Void p) {
		final JCSwitch switchStatement = setGeneratedBy(M(node).Switch(build(node.getExpression(), JCExpression.class), build(node.getCases(), JCCase.class)), source);
		return switchStatement;
	}

	@Override
	public JCTree visitSynchronized(final lombok.ast.Synchronized node, final Void p) {
		final JCBlock block = setGeneratedBy(M(node).Block(0, build(node.getStatements(), JCStatement.class)), source);
		final JCSynchronized synchronizedStatemenet = setGeneratedBy(M(node).Synchronized(build(node.getLock(), JCExpression.class), block), source);
		return synchronizedStatemenet;
	}

	@Override
	public JCTree visitThis(final lombok.ast.This node, final Void p) {
		final Name thisName = name("this");
		if (node.getType() == null) {
			return setGeneratedBy(M(node).Ident(thisName), source);
		} else {
			return setGeneratedBy(M(node).Select(build(node.getType(), JCExpression.class), thisName), source);
		}
	}

	@Override
	public JCTree visitThrow(final lombok.ast.Throw node, final Void p) {
		final JCThrow throwStatement = setGeneratedBy(M(node).Throw(build(node.getExpression(), JCExpression.class)), source);
		return throwStatement;
	}

	@Override
	public JCTree visitTry(final lombok.ast.Try node, final Void p) {
		final ListBuffer catchers = ListBuffer.lb();
		final Iterator iter = node.getCatchArguments().iterator();
		for (lombok.ast.Block catchBlock : node.getCatchBlocks()) {
			lombok.ast.Argument catchArgument = iter.next();
			catchers.append(M(node).Catch(build(catchArgument, JCVariableDecl.class), build(catchBlock, JCBlock.class)));
		}
		final JCTry tryStatement = setGeneratedBy(M(node).Try(build(node.getTryBlock(), JCBlock.class), catchers.toList(), build(node.getFinallyBlock(), JCBlock.class)), source);
		return tryStatement;
	}

	@Override
	public JCTree visitTypeParam(final lombok.ast.TypeParam node, final Void p) {
		JCTypeParameter typeParam = setGeneratedBy(M(node).TypeParameter(name(node.getName()), build(node.getBounds(), JCExpression.class)), source);
		return typeParam;
	}

	@Override
	public JCTree visitTypeRef(final lombok.ast.TypeRef node, final Void p) {
		JCExpression typeRef;
		final String typeName = node.getTypeName();
		if (TYPES.containsKey(typeName)) {
			typeRef = M(node).TypeIdent(TYPES.get(typeName));
			typeRef = setGeneratedBy(typeRef, source);
			if ("void".equals(typeName)) return typeRef;
		} else {
			typeRef = chainDots(node, node.getTypeName());
			typeRef = setGeneratedBy(typeRef, source);
			if (!node.getTypeArgs().isEmpty()) {
				typeRef = M(node).TypeApply(typeRef, build(node.getTypeArgs(), JCExpression.class));
				typeRef = setGeneratedBy(typeRef, source);
			}
		}
		for (int i = 0; i < node.getDims(); i++) {
			typeRef = setGeneratedBy(M(node).TypeArray(typeRef), source);
		}
		return typeRef;
	}

	@Override
	public JCTree visitUnary(final lombok.ast.Unary node, final Void p) {
		final String operator = node.getOperator();
		final int opCode;
		if (UNARY_OPERATORS.containsKey(operator)) {
			opCode = UNARY_OPERATORS.get(operator);
		} else {
			throw new IllegalStateException(String.format("Unknown unary operator '%s'", operator));
		}
		JCUnary unary = setGeneratedBy(M(node).Unary(opCode, build(node.getExpression(), JCExpression.class)), source);
		return unary;
	}

	@Override
	public JCTree visitWhile(final lombok.ast.While node, final Void p) {
		final JCWhileLoop whileLoop = setGeneratedBy(M(node).WhileLoop(build(node.getCondition(), JCExpression.class), build(node.getAction(), JCStatement.class)), source);
		return whileLoop;
	}

	@Override
	public JCTree visitWildcard(final lombok.ast.Wildcard node, final Void p) {
		BoundKind boundKind = BoundKind.UNBOUND;
		if (node.getBound() != null) {
			switch (node.getBound()) {
			case SUPER:
				boundKind = BoundKind.SUPER;
				break;
			default:
			case EXTENDS:
				boundKind = BoundKind.EXTENDS;
			}
		}
		final TypeBoundKind kind = setGeneratedBy(M(node).TypeBoundKind(boundKind), source);
		final JCWildcard wildcard = setGeneratedBy(M(node).Wildcard(kind, build(node.getType(), JCExpression.class)), source);
		return wildcard;
	}

	@Override
	public JCTree visitWrappedExpression(final lombok.ast.WrappedExpression node, final Void p) {
		final JCExpression expression = new TreeCopier(M(node)).copy((JCExpression) node.getWrappedObject());
		return expression;
	}

	@Override
	public JCTree visitWrappedMethodDecl(final lombok.ast.WrappedMethodDecl node, final Void p) {
		MethodSymbol methodSymbol = (MethodSymbol) node.getWrappedObject();
		Type mtype = methodSymbol.type;

		if (node.getReturnType() == null) {
			node.withReturnType(Type(fixLeadingDot(node, M(node).Type(mtype.getReturnType()))));
		}
		if (node.getThrownExceptions().isEmpty()) for (JCExpression expr : M(node).Types(mtype.getThrownTypes())) {
			node.withThrownException(Type(fixLeadingDot(node, expr)));
		}
		if (node.getArguments().isEmpty()) for (JCVariableDecl param : M(node).Params(mtype.getParameterTypes(), methodSymbol)) {
			node.withArgument(Arg(Type(fixLeadingDot(node, param.vartype)), As.string(param.name)));
		}
		if (node.getTypeParameters().isEmpty()) for (JCTypeParameter typaram : M(node).TypeParams(mtype.getTypeArguments())) {
			final lombok.ast.TypeParam typeParam = TypeParam(As.string(typaram.name));
			for (JCExpression expr : typaram.bounds) {
				typeParam.withBound(Type(fixLeadingDot(node, expr)));
			}
			node.withTypeParameter(typeParam);
		}

		final JCModifiers mods = M(node).Modifiers(methodSymbol.flags() & (~Flags.ABSTRACT), build(node.getAnnotations(), JCAnnotation.class));
		final JCExpression restype = build(node.getReturnType());
		final Name name = methodSymbol.name;
		final List thrown = build(node.getThrownExceptions(), JCExpression.class);
		final List typarams = build(node.getTypeParameters(), JCTypeParameter.class);
		final List params = build(node.getArguments(), JCVariableDecl.class);
		JCBlock body = null;
		if (!node.noBody()) {
			body = M(node).Block(0, build(node.getStatements(), JCStatement.class));
		}
		final JCMethodDecl method = M(node).MethodDef(mods, name, restype, typarams, params, thrown, body, null);
		return method;
	}

	@Override
	public JCTree visitWrappedStatement(final lombok.ast.WrappedStatement node, final Void p) {
		final JCStatement statement = new TreeCopier(M(node)).copy((JCStatement) node.getWrappedObject());
		return statement;
	}

	@Override
	public JCTree visitWrappedTypeRef(final lombok.ast.WrappedTypeRef node, final Void p) {
		JCExpression typeRef = null;
		if (node.getWrappedObject() instanceof Type) {
			typeRef = fixLeadingDot(node, M(node).Type((Type) node.getWrappedObject()));
		} else if (node.getWrappedObject() instanceof JCExpression) {
			typeRef = new TreeCopier(M(node)).copy((JCExpression) node.getWrappedObject());
		}
		for (int i = 0; i < node.getDims(); i++) {
			typeRef = setGeneratedBy(M(node).TypeArray(typeRef), source);
		}
		return typeRef;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy